# O(kn) defsolution(a): i, j = 0, 0 indice = {} ret = 0 while j < len(a): if a[j] in indice: i = indice[a[j]] # reconstruct the indice map indice = {a[k]: k for k inrange(i+1, j+1)} else: # only add the current element indice[a[j]] = j ret = max(ret, len(indice)) j += 1 return ret
# O(n) defsolution2(a): i, j = 0, 0 indice = {} ret = 0 while j < len(a): if a[j] in indice: # once we find a duplicate key # then valid path must be the length between these two key minus 1 i = max(indice[a[j]], i) ret = max(ret, j-i+1) indice[a[j]] = j+1 j += 1 return ret
对 i 做二分搜索: - 若 B[j−1]≤A[i] 且 A[i−1]≤B[j],找到中位数 - 若 B[j−1]>A[i],需要把 i 向右移(二分) - 若 A[i−1]>B[j],需要把 i 向左移(二分)
注意: - imin, imax, half_len = 0, m, (m+n+1)//2 - i = (imin+imax)//2, j = half_len – i - if i < m and nums2[j-1] > nums1[i]: imin = i + 1 # binary search - elif i > 0 and nums1[i-1] > nums2[j]: imax = i - 1 # binary search
defsolution(nums1, nums2): m, n = len(nums1), len(nums2) if m > n: nums1, nums2, m, n = nums2, nums1, n, m imin, imax, half_len = 0, m, (m + n + 1) // 2 while imin <= imax: i = (imin + imax) // 2 j = half_len - i if i > 0and nums1[i - 1] > nums2[j]: imax = i - 1 elif i < m and nums1[i] < nums2[j - 1]: imin = i + 1 else: if i == 0: max_of_left = nums2[j - 1] elif j == 0: max_of_left = nums1[i - 1] else: max_of_left = max(nums1[i - 1], nums2[j - 1])
if (m + n) % 2 == 1: return max_of_left
if i == m: min_of_right = nums2[j] elif j == n: min_of_right = nums1[i] else: min_of_right = min(nums1[i], nums2[j])
# O(n^2) defsolution(s): n = len(s) dp = [[0] * n for i inrange(n+1)] ret = "" max_len = 0 # i is the length, j is the start position for i inrange(1, len(s)+1): for j inrange(len(s)-i+1): # case 1, single char if i == 1: dp[i][j] = 1 # case 2, continuous smae char elif i == 2: if s[j] == s[j+1]: dp[i][j] = 2 else: if dp[i-2][j+1] > 0and s[j] == s[j+i-1]: dp[i][j] = dp[i-2][j+1] + 2 if dp[i][j] > max_len: max_len = dp[i][j] ret = s[j:j+i] return ret
isMatch (recursive with memo) O(MN)
加备忘录避免重复检查。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
defsolution(s, p): memo = {} m, n = len(s), len(p)
defrecursive(i, j): if (i, j) notin memo: if j == n: ans = i == m else: first_match = i < m and p[j] in (s[i], '.') if j + 1 < n and p[j + 1] == '*': ans = recursive( i, j + 2) or first_match and recursive(i + 1, j) else: ans = first_match and recursive(i + 1, j + 1) memo[i, j] = ans return memo[i, j]
return recursive(0, 0)
maxArea (trick) O(n)
令 i = 0,j = len(heights)-1。每次把较矮的那一根向中间移动,重新计算最大面积。因为如果下一根比当前还矮,宽度变小、高度也没增加,体积不可能更大。
# O(n) defsolution(height): i, j = 0, len(height) - 1 ret = min(height[j], height[i]) * (j-i) while i < j: ret = max(ret, min(height[i], height[j]) * (j-i)) if height[i] < height[j]: i += 1 else: j -= 1 return ret
(mark) threeSum (trick) O(n^2)
先排序,然后三指针 i, j, k。固定 i 后,j = i+1,k = n-1,目标是让 nums[j] + nums[k] = -nums[i]:和偏小就 j++,和偏大就 k--(因为已排序)。
# O(n^2) sort defsolution(nums): n = len(nums) nums.sort() ret = [] for i inrange(n-2): if i > 0and nums[i] == nums[i-1]: # avoid repeat continue j, k = i+1, n-1 while j < k: s = nums[i] + nums[j] + nums[k] if s < 0: j += 1 elif s > 0: k -= 1 else: ret.append([nums[i], nums[j], nums[k]]) while j < k and nums[j] == nums[j+1]: # avoid repeat j += 1 while j < k and nums[k] == nums[k-1]: # avoid repeat k -= 1 j += 1 k -= 1 return ret
defsolution(digits): ret = [] ifnot digits: return ret
defrecursion(prefix, digits): ifnot digits: ret.append(prefix) else: for c in phone[digits[0]]: recursion(prefix+c, digits[1:]) recursion("", digits) return ret
removeNthFromEnd (trick) O(n)
双指针 p, q:先让 p 向前走 n 步,再让两个指针一起走,当 p 走到末尾时,q 正好停在倒数第 n 个节点。
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(head, n): t = ListNode(None) t.next = head p = t q = t for _ inrange(n): p = p.next while p.next: q = q.next p = p.next q.next = q.next.next return t.next
generateParenthesis (recursive) O(4^n/√2)
用计数器 n 记录还可用的左括号数量,k 记录已经放下、待匹配的左括号数量。 - n == 0 且 k == 0:输出 - n == 0 且 k > 0:recursive(n, k-1),加 ‘)’ - n > 0 且 k == 0:recursive(n-1, k+1),加 ‘(‘ - 否则两个分支都试:recursive(n-1, k+1) 加 ‘(‘ 和 recursive(n, k-1) 加 ‘)’
defrecursion(prefix, i, j): # i means the assigned number of "(" and don't have ")" # j means the available number of "(" if i==0and j == 0: ret.append(prefix) elif i == 0: recursion(prefix+"(", i+1, j-1) elif j == 0: recursion(prefix+")", i-1, j) else: recursion(prefix+"(", i+1, j-1) recursion(prefix+")", i-1, j)
defrecursion(i, j): if j < i: return -1 m = (i+j)//2 if nums[m] == target: return m # target locates at non-axis side (and is left side) elif nums[i] <= target < nums[m]: return recursion(i, m-1) # target locates at non-axis side (and is right side) elif nums[m] < target <= nums[j]: return recursion(m+1, j) # target locates at axis side (and is right side) elif nums[m] > nums[j]: return recursion(m+1, j) # target locates at axis side (and is left side) else: return recursion(i, m-1) return recursion(0, len(nums)-1)
defsolution(nums, target): defrecursiveLeft(s, e): if e < s: return s m = (s+e)//2 if nums[m] < target: return recursiveLeft(m+1, e) else: return recursiveLeft(s, m-1)
defrecursiveRight(s, e): if e < s: return e m = (s+e)//2 if nums[m] <= target: return recursiveRight(m+1, e) else: return recursiveRight(s, m-1)
left, right = recursiveLeft(0, len(nums)-1), recursiveRight(0, len(nums)-1) # once we cannot found the value, the left will right-1 return [left, right] if left <= right else [-1, -1]
combinationSum (dfs) O(exponential)
外面套个 for 循环依次调用递归即可。
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(candidates, target): ret = []
defrecursion(prefix, i, target): if target == 0: ret.append(prefix) for i inrange(i, len(candidates)): num = candidates[i] if target - num >= 0: recursion(prefix+[num], i, target-num) recursion([], 0, target) return ret
firstMissingPositive (trick: hash with mod position) O(n)
最大挑战是只能用常数额外空间,不能开 O(n) 哈希表。因此用输入数组本身充当哈希表。
做法:先把所有 <0 或 >=n 的位置置 0,然后 nums[nums[i] % n] += n,用这种方式标记某个 bin 已经出现过。最后遍历,第一个值仍小于 n 的下标就是答案。
1 2 3 4 5 6 7 8 9 10 11 12 13
defsolution(nums): nums.append(0) # very important, for example, [1] n = len(nums) for i inrange(n): # delete those useless elements if nums[i] < 0or nums[i] >= n: nums[i] = 0 # use the index as the hash to record the frequency of each number for i inrange(n): nums[nums[i] % n] += n # +n and %n to make the original value do not be overlaped for i inrange(1, n): if nums[i] < n: return i return n
defsolution(height): height = [0] + height + [0] n = len(height) ret = 0 max_left = [0] * n # record the max height from left max_right = [0] * n # record the max height from right cur_max = height[0] for i inrange(n): cur_max = max(cur_max, height[i]) max_left[i] = cur_max cur_max = height[-1] for i inrange(n-1, -1, -1): cur_max = max(cur_max, height[i]) max_right[i] = cur_max ret += min(max_left[i], max_right[i]) - height[i] return ret
Permute (loop call recusive) O(2^n)
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(nums): ret = [] n = len(nums)
defrecursion(prefix, remaining): ifnot remaining: ret.append(prefix) else: for k inrange(len(remaining)): recursion(prefix+[remaining[k]], remaining[:k] + remaining[k+1:]) recursion([], nums) return ret
Rotate (trick) O(n^2)
先反转再转置(reverse + transpose)。
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(matrix): n = len(matrix) i, j = 0, n - 1 # swap while i < j: matrix[i], matrix[j] = matrix[j], matrix[i] i += 1 j -= 1 # transpose for i inrange(n): for j inrange(i, n): matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
defsolution(strs): ret = defaultdict(list) for s in strs: ret[tuple(sorted(s))].append(s) returnlist(ret.values())
** 必须用 sorted(s);用 set(s) 不行(会丢失字符频次)。
(mark) maxSubArray (trick) O(n)
从左到右扫一遍,用一个累计 sum:只要左边累计是正的就保留,否则把累计的负值丢弃从头开始。
转移:nums[i] = max(0, nums[i-1]) + nums[i]
每段连续正子串里取最大:ret = max(ret, nums[i])。
1 2 3 4 5 6 7
defsolution(nums): cur_sum = 0 max_v = - sys.maxsize for num in nums: cur_sum = max(0, cur_sum) + num max_v = max(max_v, cur_sum) return max_v
canJump (greedy) O(n)
从左往右扫,维护”当前能到达的最远位置”。每遇到新位置就更新。能到末尾就返回 true。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
defsolution(nums): m = 0 for i inrange(0, len(nums)): if i > m: returnFalse m = max(m, i+nums[i]) returnTrue
defsolution(nums): i, max_i = 0, 0 while i <= max_i and i < len(nums) and max_i < len(nums)-1: max_i = max(max_i, i+nums[i]) i += 1 return max_i >= len(nums) - 1
defsolution(intervals): intervals.sort(key=lambda x: x[0]) merged = [] for interval in intervals: ifnot merged or merged[-1][1] < interval[0]: merged.append(interval) else: merged[-1][1] = max(merged[-1][1], interval[1])
return merged
defsolution(intervals): intervals.sort(key=lambda x: x[0]) ret = [] while intervals: interval_1 = intervals.pop(0) if intervals and interval_1[1] >= intervals[0][0]: intervals[0][0] = interval_1[0] intervals[0][1] = max(intervals[0][1], interval_1[1]) else: ret.append(interval_1) return ret
uniquePaths (dp) O(m+n)
dp[i][j] = dp[i][j-1] + dp[i-1][j]
1 2 3 4 5 6 7 8 9 10
defsolution(m, n): dp = [[0] * n for _ inrange(m)] for i inrange(m): dp[i][0] = 1 for j inrange(n): dp[0][j] = 1 for i inrange(1, m): for j inrange(1, n): dp[i][j] = dp[i][j-1] + dp[i-1][j] return dp[-1][-1]
minPathSum (dp) O(mn)
dp[i][j] = min(dp[i][j-1], dp[i-1][j]) + m[i][j]
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(grid): m, n = len(grid), len(grid[0]) dp = [[0]*n for _ inrange(m)] dp[0][0] = grid[0][0] for i inrange(1, m): dp[i][0] = dp[i-1][0] + grid[i][0] for j inrange(1, n): dp[0][j] = dp[0][j-1] + grid[0][j] for i inrange(1, m): for j inrange(1, n): dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] return dp[-1][-1]
climbStairs (dp) O(n)
dp[i] = dp[i-1] + dp[i-2], dp[0]=1, dp[1] = 1
1 2 3 4 5 6 7 8 9
defsolution(n): if n == 1: return1 dp = [0] * n dp[0], dp[1] = 1, 2 for i inrange(2, n): dp[i] = dp[i-1] + dp[i-2]
defminWindow(self, s, t): """ :type s: str :type t: str :rtype: str """ import sys import collections m = collections.defaultdict(int) # m just like a balance wallet # we first add chars of T into it # then once we encounter chars in S # we minus from m # so for m>0 menas there is still char we need to find # m<0 means we remove much more than we need in T for c in t: m[c] += 1 j = 0
# identify how many remaining chars in T we still need to find count = len(t) minLen = sys.maxsize minStart = 0 for i inrange(len(s)): # only when m[s[i]] > 0, means remaining chars in t if m[s[i]] > 0: count -= 1 m[s[i]] -= 1 # we have found all chars in T, we start to move j while count == 0: if (i - j + 1) < minLen: minLen = i-j+1 minStart = j m[s[j]] += 1 # when m[s[i]] > 0, means we remove too much target chars # we increase count to mark there are chars we need to find if m[s[j]] > 0: count += 1 j += 1
if minLen < sys.maxsize: return s[minStart:minStart+minLen] return""
defsolution(s, t): from collections import Counter import sys
n = len(s) i, j = 0, 0 c_t = Counter(t) count = len(t) b, l = 0, sys.maxsize while j < n: if c_t[s[j]] > 0: count -= 1 c_t[s[j]] -= 1
whilenot count: if (j-i+1) < l: l = j-i+1 b = i c_t[s[i]] += 1 if c_t[s[i]] > 0: count += 1 i += 1 j += 1 if l < sys.maxsize: return s[b:b+l] return""
Subsets (dfs) O(2^n)
跟全排列类似,但中间节点也要输出。
1 2 3 4 5 6 7 8 9 10
defsolution(nums): n = len(nums) ret = []
defrecursion(prefix, i): ret.append(prefix) for j inrange(i, n): recursion(prefix+[nums[j]], j+1) recursion([], 0) return ret
defsolution(board, word): m, n = len(board), len(board[0])
defrecursion(i, j, idx): if idx == len(word): returnTrue board[i][j] = "#" if i+1 < m and board[i+1][j] == word[idx] and recursion(i+1, j, idx+1): returnTrue if j+1 < n and board[i][j+1] == word[idx] and recursion(i, j+1, idx+1): returnTrue if i-1 >= 0and board[i-1][j] == word[idx] and recursion(i-1, j, idx+1): returnTrue if j-1 >= 0and board[i][j-1] == word[idx] and recursion(i, j-1, idx+1): returnTrue board[i][j] = word[idx-1] returnFalse
for i inrange(m): for j inrange(n): if board[i][j] == word[0] and recursion(i, j, 1): returnTrue returnFalse
defflatten(node): ifnot node.left andnot node.right: return node if node.left: # get the deepest left node to append to its first right node tmp_node = flatten(node.left) tmp_node.right = node.right # append it right to the deepest node's right node.right = node.left # append the top left to its right node.left = None if node.right: # return deepest right node return flatten(node.right)
defrecursive(root): nonlocal max_v ifnot root: return0 else: left = recursive(root.left) right = recursive(root.right) max_v = max(max_v, left + right + root.val) returnmax(left + root.val, right + root.val, 0)
recursive(root) return max_v
longestConsecutive (hash) O(n)
把数组转成 set。遍历时若 nums[i]-1 在 set 里就跳过;只有遇到序列起点(即没有 nums[i]-1)时才开始向后逐 +1 计数,求出连续长度。
1 2 3 4 5 6 7 8 9 10 11 12 13
defsolution(nums): ifnot nums: return0 set_nums = set(nums) max_v = 0 for num in nums: if num - 1notin set_nums: count = 1 while num + 1in set_nums: num += 1 count += 1 max_v = max(max_v, count) return max_v
defsolution(s, wordDict): n = len(s) dp = [False] * (n + 1) dp[0] = True for i inrange(1, n + 1): for w in wordDict: if i >= len(w) and dp[i - len(w)] and s[i - len(w):i] == w: dp[i] = True return dp[-1]
所以两者相遇后,再让一个新指针从 head 出发,与 slow 同步前进,相遇点就是环的入口(因为 B + A = N)。
1 2 3 4 5 6 7 8 9 10 11 12 13
defsolution(head): p = head q = head t = head while p and q and p.nextand q.nextand q.next.next: p = p.next.next q = q.next if q == p: while q != t: q = q.next t = t.next return t returnNone
defsolution(nums): maximum = b = s = nums[0] for num in nums[1:]: b, s = max(num, b * num, s * num), min(num, b * num, s * num) maximum = max(maximum, b) return maximum
Boyer-Moore 投票法。维护 value 和 count:count == 0 时把 value 置为 nums[i] 并 count += 1;nums[i] == value 则 count += 1,否则 count -= 1。
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(nums): cur_value = nums[0] cur_num = 1 for num in nums[1:]: if num != cur_value: cur_num -= 1 if cur_num == -1: cur_value = num cur_num = 1 else: cur_num += 1 return cur_value
def__init__(self, val): self.next = [None] * 26 self.val = val
classTrie(object):
def__init__(self): """ Initialize your data structure here. """ self.root = TrieNode(False)
definsert(self, word): """ Inserts a word into the trie. :type word: str :rtype: None """ node = self.root for w in word: idx = ord(w) - ord('a') ifnot node.next[idx]: node.next[idx] = TrieNode(False) node = node.next[idx] node.val = True
defsearch(self, word): """ Returns if the word is in the trie. :type word: str :rtype: bool """ node = self.root for w in word: idx = ord(w) - ord('a') ifnot node.next[idx]: returnFalse node = node.next[idx] return node.val
defstartsWith(self, prefix): """ Returns if there is any word in the trie that starts with the given prefix. :type prefix: str :rtype: bool """ node = self.root for w in prefix: idx = ord(w) - ord('a') ifnot node.next[idx]: returnFalse node = node.next[idx] returnTrue
# O(klogk+2(n-k)logk) defsolution(nums, k): import heapq k_heap = nums[0:k] heapq.heapify(k_heap) for i inrange(k, len(nums)): heapq.heappush(k_heap, nums[i]) heapq.heappop(k_heap) return heapq.heappop(k_heap)
# O(n) defsolution(nums, k):
defrecursive(nums, k): pivot = nums.pop(len(nums) // 2) right = [num for num in nums if num > pivot] lr = len(right) if k == lr + 1: return pivot elif k < lr + 1: return recursive(right, k) else: left = [num for num in nums if num <= pivot] return recursive(left, k - lr - 1)
defrecursive(root): nonlocal low_desc ifnot root: return0 ret = recursive(root.left) if ret < 2: ret += recursive(root.right) if root.val in (q.val, p.val): ret += 1 if ret == 2andnot low_desc: low_desc = root return ret
ret = [max(nums[:k])] for i inrange(1, len(nums) - k + 1): if nums[i + k - 1] >= ret[-1]: ret.append(nums[i + k - 1]) elif nums[i - 1] < ret[-1]: ret.append(ret[-1]) else: ret.append(max(nums[i:i + k])) return ret
defsolution(nums): n = len(nums) if n == 0or n == 1: return nums i = 0 while i < n and nums[i] != 0: i += 1 j = i whileTrue: while j < n and nums[j] == 0: j += 1 if j >= n: break nums[i], nums[j] = nums[j], nums[i] i += 1
defsolution(nums): n = len(nums) if n == 0or n == 1: return nums i = 0 while i < n and nums[i] != 0: i += 1 for j inrange(i + 1, n): if nums[j] != 0: nums[i], nums[j] = nums[j], nums[i] i += 1
findDuplicate (trick) O(n)
转化为”链表找环入口”:把下标 i 看成节点,i → nums[i]。因为有重复值,这条链一定有环;环的入口就是重复值。
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(nums): slow = nums[0] fast = nums[nums[0]] while fast != slow: fast = nums[nums[fast]] slow = nums[slow] slow = 0 while slow != fast: slow = nums[slow] fast = nums[fast] return slow
MedianFinder (trick) O(nlogn)
解法 1:维护一个有序列表,每次用二分找到插入位置。
解法 2:双堆 —— 大顶堆(存较小一半)+ 小顶堆(存较大一半)。每次插入时若两堆大小相等,先入大堆再 pop 一个最大值送进小堆;否则反之。求中位数:两堆等长时取两个堆顶平均,否则取大堆堆顶。
defserialize(self, root): """Encodes a tree to a single string. :type root: TreeNode :rtype: str """ ifnot root: return'' out = [] queue = collections.deque([root]) while queue: node = queue.popleft() out.append(str(node.val) if node else'#') if node: queue.append(node.left) queue.append(node.right) return' '.join(out)
defdeserialize(self, data): """Decodes your encoded data to tree. :type data: str :rtype: TreeNode """ ifnot data: returnNone out = data.split() bfs = [TreeNode(int(i)) if i != '#'elseNonefor i in out] slow_idx = 0# the id in array nodex fast_idx = 1# the id in array bfs root = bfs[0] nodes = [root] while slow_idx < len(nodes): node = nodes[slow_idx] slow_idx += 1# each time we handle one node in nodes node.left = bfs[fast_idx] node.right = bfs[fast_idx + 1] fast_idx += 2# each time we only handle two nodes in bfs if node.left: nodes.append(node.left) if node.right: nodes.append(node.right) return root
lengthOfLIS(dp)
lengthOfLIS(dp) O(n^2)
dp[i] 表示以位置 i 结尾的最长上升子序列长度。每次把当前值与之前所有值比较,若当前更大就尝试更新:
1 2 3 4 5 6 7 8 9 10 11 12
deflengthOfLIS(nums): iflen(nums) == 0: return0 dp = [0] * len(nums) dp[0] = 1 for i inrange(1, len(nums)): max_t = 0 for j inrange(0, i): if nums[i] > nums[j]: max_t = max(max_t, dp[j]) # # longest length till now plus current dp[i] = max_t + 1 returnmax(dp)
# o(n^2) defsolution(nums): dp = [1] * len(nums) for i inrange(1, len(nums)): for j inrange(i): if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1) returnmax(dp)
# O(n * logn) defsolution(nums): dp = [0] * len(nums) size = 0 for n in nums: i, j = 0, size while i != j: m = (i + j) // 2 if dp[m] < n: i = m + 1 else: j = m dp[i] = n size = max(size, i + 1) return size
defremoveInvalidParentheses(self, s): """ :type s: str :rtype: List[str] """ defremoveHelper(s, output, iStart, jStart, openParen, closedParen): numOpenParen, numClosedParen = 0, 0 for i inrange(iStart, len(s)): if s[i] == openParen: numOpenParen += 1 if s[i] == closedParen: numClosedParen += 1 # We have only ONE extra closed paren we need to remove if numClosedParen > numOpenParen: print(s) if openParen == '(': print("positive") elif openParen == ')': print('negative') print("i=", i, numOpenParen, numClosedParen) # Try removing this ONE closed paren at each position, skipping duplicates print(jStart, i) # jStart: always to search the first closedParen which can be removed for j inrange(jStart, i+1): # <= # can be the first char, # or the char which previous char isn't closedParen, removing each one of the consequtive closedParen actually is the same if s[j] == closedParen and (j == jStart or s[j-1] != closedParen): # since when j == jStart, there isn't j-1 # Recursion: iStart = i since we now have valid # closed parenthesis thru i. jStart = j prevents duplicates # at the next recursion, we only need to search the iStart from the current i, and search the jStart from the current j # since we found the first invalid closedParen at the i, and we have removed a closedParen at j print("remove, j=", j, s[j]) removeHelper(s[:j]+s[j+1:], output, i, j, openParen, closedParen) return reversed = s[::-1] print(reversed, "now out of the loop") if openParen == '(': removeHelper(reversed, output, 0, 0, ')', '(') else: output.append(reversed)
defsolution(num): dp = [0] * (num + 1) for i inrange(1, num + 1): dp[i] = dp[i // 2] + i % 2 return dp
topKFrequent(heap) O(nlogn)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from collections import defaultdict import heapq
defsolution(nums, k): hash_map = defaultdict(int) for num in nums: hash_map[num] += 1 ret = [] i = 0 for key, val in hash_map.items(): if i < k: heapq.heappush(ret, (val, key)) else: heapq.heappushpop(ret, (val, key)) i += 1 return [v for k, v in ret]
decodeString(stack) O(n)
栈解法:遇到 ‘]’ 时 pop 出 ‘[‘ 之前的字符串,再继续 pop 数字字符拼成倍数,把字符串重复后压回栈。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
defsolution(s): stack = [""] num = "" for c in s: if c.isdigit(): num += c elif c == "[": stack.extend([num, ""]) num = "" elif c == "]": chars = stack.pop() n_chars = stack.pop() stack[-1] += chars * int(n_chars) else: stack[-1] += c return stack.pop()
nums = sorted(nums, reverse=True) dp[0][nums[0]] = True for i inrange(1, len(nums)): dp[i][nums[i]] = True for j inrange(scale - 1, 0, -1): if dp[i - 1][j]: dp[i][j] = True if j > nums[i] and dp[i - 1][j - nums[i]]: dp[i][j] = True if dp[i][-1]: returnTrue return dp[-1][-1]
defsolution(nums):
defrecursive(nums, target): for i, num inenumerate(nums): if num > target: returnFalse elif num == target: returnTrue elif recursive(nums[i + 1:], target - nums[i]): returnTrue returnFalse
defsolution(s, p): import collections ret = [] p_counter = collections.Counter(p) s_counter = collections.Counter(s[:len(p) - 1]) for i inrange(len(p) - 1, len(s)): s_counter[s[i]] += 1 pre_i = i - len(p) + 1 if s_counter == p_counter: ret.append(pre_i) s_counter[s[pre_i]] -= 1 if s_counter[s[pre_i]] == 0: del s_counter[s[pre_i]] return ret
defsolution(s, p): l = len(p) p_frequency = [0] * 26 ss_frequency = [0] * 26 res = [] for c in p: p_frequency[ord(c) - 97] += 1 for c in s[0:l]: ss_frequency[ord(c) - 97] += 1 if p_frequency == ss_frequency: res.append(0)
for i inrange(1, len(s) - l + 1): ss_frequency[ord(s[i - 1]) - 97] -= 1 ss_frequency[ord(s[i + l - 1]) - 97] += 1 if p_frequency == ss_frequency: res.append(i)
return res
findDisappearedNumbers(trick) (n)
遍历数组,把”已出现”的对应位置标记为负数。最后剩下正数的下标 +1 就是缺失的数。
1 2 3 4 5 6 7 8 9 10 11 12
defsolution(nums): n = len(nums) for i inrange(n): _num = abs(nums[i]) if _num <= n: nums[_num - 1] = -abs(nums[_num - 1])
ret = [] for i inrange(n): if nums[i] > 0: ret.append(i + 1) return ret
# O(n^2) defsolution(nums, k): n = len(nums) ret = 0 dp = [[0] * (n + 1) for _ inrange(n)] # (start_pos, len) for i inrange(1, n + 1): for j inrange(0, n - i + 1): if i == 1: dp[j][i] = nums[j] else: dp[j][i] = nums[j] + dp[j + 1][i - 1] if dp[j][i] == k: ret += 1 return ret
# O(n) defsolution(nums, k): cache = {0: 1} cur_sum = 0 ret = 0 for n in nums: cur_sum += n ret += cache.get(cur_sum - k, 0) cache[cur_sum] = cache.get(cur_sum, 0) + 1 return ret
defsolution(nums): n = len(nums) if n <= 1: return0 right = 0 cur_max = nums[0] for i inrange(1, n): if nums[i] < cur_max: right = i cur_max = max(cur_max, nums[i])
cur_min = nums[-1] left = len(nums)-1 for i inrange(n - 2, -1, -1): if nums[i] > cur_min: left = i cur_min = min(cur_min, nums[i]) returnmax(right - left + 1, 0)
defsolution(tasks, n): cache = [0] * 26 for c in tasks: cache[ord(c) - ord('A')] += 1 cache.sort(reverse=True) max_v = cache[0] - 1 idle_slots = max_v * n for i inrange(1, len(cache)): if cache[i] == 0: break idle_slots -= min(cache[i], max_v) return idle_slots + len(tasks) if idle_slots > 0elselen(tasks)
countSubstrings
countSubstrings() O(n^2)
1 2 3 4 5 6 7 8 9 10 11 12 13
n = len(s) if n <= 1: return n dp = [[0] * (n + 1) for _ inrange(n)] # (start_pos, len) ret = 0 for i inrange(1, n + 1): for j inrange(0, n - i + 1): if i == 1or (i == 2and s[j] == s[j + 1]) or (s[j] == s[j + i - 1] and dp[j + 1][i - 2]): dp[j][i] = 1 ret += 1 return ret
defsolution(T): ret = [0] * len(T) stack = [(T[0], 0)] for i inrange(1, len(T)): top = stack[-1] if T[i] > top[0]: while stack and T[i] > stack[-1][0]: _t = stack.pop() ret[_t[1]] = i - _t[1] stack.append((T[i], i)) return ret