763. Partition Labels
https://leetcode.com/problems/partition-labels/
A string
S
of lowercase letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.
最好的情况,肯定是每个字符分为一组。但如果同个字母在字符串中出现两次以上,那么从第一次到最后一次之前的字符串,会被分为同一组。假设把S[i:j]
划为一个分组,其中的字母在之后都不再出现,那它就能成为一个分组。算法非常简单,时间复杂度为$O(N)$。
def partitionLabels(self, S: str) -> List[int]:
# partition each letter as a part at first
# the last place of appearance of each word
appear = {}
for i in range(len(S)-1, -1, -1):
if S[i] not in appear:
appear[S[i]] = i
# the current part is S[start:end+1]
start, end = 0, 0
rtn = []
for i, w in enumerate(S):
end = max(end, appear[S[i]])
if i == end:
rtn.append(end-start+1)
start, end = i+1, i+1
return rtn
921. Minimum Add to Make Parentheses Valid
https://leetcode.com/problems/minimum-add-to-make-parentheses-valid/
Given a string
S
of'('
and')'
parentheses, we add the minimum number of parentheses ('('
or')'
, and in any positions ) so that the resulting parentheses string is valid.Formally, a parentheses string is valid if and only if:
- It is the empty string, or
- It can be written as
AB
(A
concatenated withB
), whereA
andB
are valid strings, or- It can be written as
(A)
, whereA
is a valid string.Given a parentheses string, return the minimum number of parentheses we must add to make the resulting string valid.
非常经典的题目。从左到右扫描字符串,如果碰到的)
多于(
,那么必须在左边补上若干个(
。如果(
多于)
则不用,因为可能右边没扫到的地方有)
来匹配。扫到最后,如果(
的数目更多,则需要在右边补上对应数量的)
,使得括号数目相等。
def minAddToMakeValid(self, S: str) -> int:
left = 0
ans = 0
for each in S:
if each == '(':
left += 1
else:
if left > 0:
left -= 1
else:
ans += 1
return ans + left
406. Queue Reconstruction by Height
https://leetcode.com/problems/queue-reconstruction-by-height/
Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers
(h, k)
, whereh
is the height of the person andk
is the number of people in front of this person who have a height greater than or equal toh
. Write an algorithm to reconstruct the queue.Example
Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] Output: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
要做出这道题,需要认识到以下两个事实:
- 假如列表里最小的身高是
h
,且只有一个人身高是h
。那么他排在第k
位,他的标号就是(h,k)
,因为他前面的人都高过他。 - 假如一个人的标号是
(h,k)
,那么有一个身高为h',h'<h
的人插入队列,不会影响他的标号。
从这两点,我们可以设计这样的队列插入方法:
- 将
people
按身高从高到低排。如果身高一样,就按k
值从小到大排。 - 每轮依次从排序后的
people
中取出一人,假设是(h,k)
,将他插入到结果队列中的第k
个位置中。
这是因为,取出的(h,k)
后面所有人,要么身高比他低,插到哪里都不影响他的标号;要么身高和他一样但是k
值比他低,只能插到他后面的位置。总之,后面的人插入时不会影响前面的人的标号在当前队列中的正确性。因此只要按照这个办法,将所有人(正确地)插入队列中后,就能在保证所有人的标号都对的前提下排好队了。
代码的sorted
部分,我本来用了functools
库中的cmp_to_key
写比较函数。但是看了@StefanPochmann的回答以后,我发现有简洁得多的写法(此人写出了许多令人赏心悦目的简洁代码)。以下代码借鉴了他的sorted
写法。
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
sorted_people = sorted(people, key=lambda x: (-x[0], x[1]))
ans = []
for each in sorted_people:
ans.insert(each[1], each)
return ans