defgroupAnagrams(self, strs: List[str]) -> List[List[str]]: map = {} for item in strs: v = self.str2value(item) if v inmap.keys(): map[v].append(item) else: map[v] = [item] returnlist(map.values()) defstr2value(self, stR:str) -> int : res = 0 for char in stR: index = ord(char)-ord('a') res += 10**(index) return res*len(stR)
第一次的思路就是 把一个 str 得到一个顺序无关的哈希值。但是复杂度好像有点高。
更好的实现方式:使用了 from collections import defaultdict 内置函数
classSolution: defgroupAnagrams(self, strs: List[str]) -> List[List[str]]: dic = collections.defaultdict(list) for s in strs: index = ''.join(sorted(s)) dic[index].append(s) returnlist(dic.values())
这个题要求了时间复杂度为O(n) 所以不考虑排序的方法,首先用 set 对 nums 去重,然后找到 所有序列开头的数字 并计算 这个序列的长度,由于每个数仅进入一次内层循环,所以时间复杂度符合要求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: deflongestConsecutive(self, nums: List[int]) -> int: res = 0 nums_set = set(nums) for i in nums_set: if i-1in nums_set: continue # 否则说明这个数是 一个序列的开头 l = 1 p = i+1 while p in nums_set: l+=1 p+=1 res = max(res,l) return res
下面这个节省20ms的时间
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: deflongestConsecutive(self, nums: List[int]) -> int: res = 0 nums_set = set(nums) for i in nums_set: if i-1in nums_set: continue # 否则说明这个数是 一个序列的开头 p = i+1 while p in nums_set: p+=1 res = max(res,p-i) return res
这个算法的关键是找到起点 避免对一个数的重复遍历
list 转 set 还有 判断 in set 的操作 时间复杂度是 O(1), 如果是用 list 的 in 时间复杂度是 O(n)
list : remove是移除 第一个 value,pop是删掉指定index的item
顺序遍历,把0移到最后
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defmoveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ i=0 last = len(nums) while i < last : if nums[i] == 0 : nums.pop(i) nums.append(0) last-=1 i-=1 i+=1
思路二 栈 遇到非零压入栈
1 2 3 4 5 6 7 8
classSolution: defmoveZeroes(self, nums: List[int]) -> None: stack_size=0 for num in nums: if num : nums[stack_size] = num stack_size+=1 nums[stack_size:len(nums)] = [0]*(len(nums)-stack_size)
classSolution: defmaxArea(self, height: List[int]) -> int: l, r = 0, len(height) - 1 ans = 0 while l < r: # w = r - l h = min(height[l], height[r]) ans = max(ans, (r - l) * h) while height[l] <= h and l < r: l += 1 while height[r] <= h and l < r: r -= 1 return ans
通过节省搜索空间的想法,还可以进一步,通过记录高度的最大值,得到最大的S,然后直接return
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: defmaxArea(self, height: List[int]) -> int: max_area = 0 l, r = 0, len(height) - 1 max_height = max(height) while l < r: if max_height * (r - l) < max_area: return max_area cur_area = min(height[l], height[r]) * (r - l) if cur_area > max_area: max_area = cur_area if height[l] > height[r]: r -= 1 else: l += 1 return max_area
classSolution: defthreeSum(self, nums: List[int]) -> List[List[int]]: nums.sort() ans = [] n = len(nums) for i inrange(n - 2): x = nums[i] if i > 0and x == nums[i - 1]: # 跳过重复数字 continue if x > 0or nums[-1]<0 : # 优化一 break if x + nums[-2] + nums[-1] < 0: # 优化二 continue j = i + 1 k = n - 1 while j < k: s = x + nums[j] + nums[k] if s > 0: k -= 1 elif s < 0: j += 1 else: # 三数之和为 0 ans.append([x, nums[j], nums[k]]) j += 1 while j < k and nums[j] == nums[j - 1]: # 跳过重复数字 j += 1 k -= 1 while k > j and nums[k] == nums[k + 1]: # 跳过重复数字 k -= 1 return ans
这个方法和 第一个复杂度都是 但是双指针要快一些啊,是因为 枚举 + 哈希表法虽是 O (n²),但哈希表的额外开销、随机内存访问导致常数项远大于双指针;1. 双指针法的「」是真 (外层 n 次,内层 n 次),且常数项极小;
classSolution: deftrap(self, height: List[int]) -> int: stack = [] ans = 0 for i,h inenumerate(height) : while stack and h > height[stack[-1]] : top = stack.pop() ifnot stack : break # 这个是重点部分 好好想一下 ans += (min(height[stack[-1]],h)-height[top])*(i-stack[-1]-1) stack.append(i) return ans
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: ans,i,l = 0,0,len(s) window = collections.deque() count = collections.defaultdict(int) while i < l : while i < l and count[s[i]] == 0 : window.append(s[i]) count[s[i]] += 1 i += 1 ans = max(len(window),ans) while i < l and count[s[i]]!=0 : f = window.popleft() count[f] -= 1 return ans
用 set(字典本身就适合处理 是否重复这样的事情)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: # 滑动窗口 left = 0 window = set() max_length = 0 for right inrange(len(s)): while s[right] in window: window.remove(s[left]) left += 1 window.add(s[right]) iflen(window) > max_length: max_length = len(window) return max_length
这个2ms 最快
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: n = len(s) if n <= 1: return n _dict = {} start = -1 res = 0 for i, c inenumerate( s ): if c in _dictand _dict[c] > start: start = _dict[c] res = max(res, i - start) _dict[c] = i return res
classSolution: deffindAnagrams(self, s: str, p: str) -> List[int]: ans = [] count = {} window = collections.deque() for c in p : count[c] = 0 for c in p : count[c] -= 1 count['other'] = 0 start = 0 for c in s : window.append(c) if c in count.keys() : count[c] += 1 while count[c] > 0 : f = window.popleft() start += 1 count[f] -= 1 else : count['other'] += 1 while count['other'] != 0 : f = window.popleft() start += 1 if f in count.keys() : count[f] -= 1 else : count['other'] -= 1 iflen(window) == len(p) : ans.append(start) return ans
classSolution: defsubarraySum(self, nums: List[int], k: int) -> int: ans,sumn = 0, 0 cnt = collections.defaultdict(int) for n in nums: cnt[sumn] += 1 sumn += n ans += cnt[sumn - k ] return ans
classSolution: defmaxSlidingWindow(self, nums: List[int], k: int) -> List[int]: q = collections.deque() ans = [] for i inrange(0,len(nums)) : while q and nums[i] >= nums[q[-1]] : q.pop() q.append(i) while q[0] <= i-k : q.popleft() if i >= k-1 : ans.append(nums[q[0]]) return ans
classSolution: defminWindow(self, s:str, t: str) -> str: # 维护一个缺少多少的表 w = collections.deque() rq = {} ansl ,l = 9999999,0 ans = '' for c in t : if c in rq.keys() : rq[c] += 1 else : rq[c] = 1 # 处理队列,保证 rq 都得是 0 for c in s : w.append(c) l += 1 if c in rq.keys() : rq[c] -= 1 while w : if w[0] in rq.keys() : print(rq[w[0]]) if w[0] in rq.keys() : if rq[w[0]] >= 0 : break else : rq[w[0]] += 1 w.popleft() l -= 1 jump = False for i in rq.values() : if i > 0 : jump = True if ansl > l and jump == False : ansl = l ans = ''.join(w) return ans
# class Solution: # def maxSubArray(self, nums: List[int]) -> int: # # 一个index左边的最小值,一个index右边的最大值 # leftMin,rightMax = [10001]*(len(nums)+1),[-10001]*(len(nums)+1) # sn = [0] * (len(nums)+1) # for i in range(len(nums)) : # sn[i+1] = nums[i] # for i in range(1,len(sn)) : # sn[i] += sn[i-1] # leftMin[0] = sn[0] # rightMax[-1] = sn[-1] # for i in range(1,len(sn)) : # leftMin[i] = min(leftMin[i-1],sn[i]) # rightMax[len(sn)-1-i] = max(rightMax[len(sn)-i],sn[len(sn)-1-i]) # ans = -99999999 # for i in range(len(sn)-1) : # if ans < rightMax[i+1] - leftMin[i] : # ans = rightMax[i+1] - leftMin[i] # return ans
维护两个太慢了,因为这个主要的约束 是 最小值在最大值的右边,通过记录最小值,然后计算 s[n] 和 min 的差 来更新 结果:
1 2 3 4 5 6 7 8
classSolution : defmaxSubArray(self, nums: List[int]) -> int : tsum, tmin, ans = 0, 0, -99999 for n in nums : tsum += n ans = max(ans,tsum-tmin) tmin = min(tmin,tsum) return ans
classSolution: defproductExceptSelf(self, nums: List[int]) -> List[int]: length = len(nums) answer = [0] * length answer[0] = 1 for i inrange(1, length): answer[i] = nums[i - 1] * answer[i - 1] R = 1 for i inreversed(range(length)): answer[i] = answer[i] * R R *= nums[i] return answer
UES
这个解法考虑了0 同时用了reduce函数可以看一下
1 2 3 4 5 6 7 8 9 10 11
classSolution: defproductExceptSelf(self, nums: List[int]) -> List[int]: if0in nums: ret= [0]*len(nums) if nums.count(0)>=2: return ret ret[nums.index(0)]=reduce(mul,(i for i in nums if i!=0),) return ret p=reduce(mul,nums,) if p!=0: return [p//i for i in nums]
Trash
用 前缀积 后缀积 来在 时间复杂度解决这个问题 但是 空间复杂度是
1 2 3 4 5 6 7 8 9 10 11
classSolution: defproductExceptSelf(self, nums: List[int]) -> List[int]: fD, bD = nums[:], nums[:] # 定义前缀后缀积 for i inrange(1,len(nums)) : fD[i] *= fD[i-1] bD[len(nums)-i-1] *= bD[len(nums)-i] ans = [ bD[1] ] for i inrange(1,len(nums)-1) : ans.append( fD[i-1] * bD[i+1] ) ans.append(fD[-2]) return ans
ans 最大的情况 就是 1,len(nums)都在 ,那么如果把 nums 中的 值 作为 index 那么肯定有 index 用不完的情况,第一个没用的就是 答案。
v[index] 是负数,那么这个index 可以直接拿来用,如果 v[i]>0 那么我们就需要把 这个 v[i] 也给记录下来。向链表一样顺着找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution: deffirstMissingPositive(self, nums: List[int]) -> int: l = len(nums) for i inrange(len(nums)) : target = nums[i]-1 if target < 0or target >= l : continue while nums[target] <= l and nums[target] > 0 : if nums[target] == target + 1 : break next_target = nums[target] - 1 nums[target] = target + 1 target = next_target nums[target] = target + 1 for i inrange(len(nums)) : if i+1 != nums[i] : return i+1 else : return l+1
题解中的原地哈希,这个比上面的方法更好
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: deffirstMissingPositive(self, nums: List[int]) -> int: n = len(nums) for i inrange(n): if nums[i] <= 0: nums[i] = n + 1 for i inrange(n): num = abs(nums[i]) if num <= n: nums[num - 1] = -abs(nums[num - 1]) for i inrange(n): if nums[i] > 0: return i + 1 return n + 1
Trash
题目中限制了空间复杂度是常数,如果不考虑空间,这个方法很快
1 2 3 4 5 6 7 8 9
classSolution: deffirstMissingPositive(self, nums: List[int]) -> int: ans = len(nums)+1 s = set(nums) for i inrange(len(nums),0,-1) : if i in s : continue else : ans = min(ans,i) return ans
classSolution: defsetZeroes(self, matrix: List[List[int]]) -> None: """ Do not return anything, modify matrix in-place instead. """ c_index = set() for i,n inenumerate(matrix) : if0in n : index = [ -1if n[index]!=0else index for index inrange(len(n)) ] [c_index.add(x) for x in index] matrix[i] = [0] * len(n) for i,n inenumerate(matrix) : for j inrange(len(n)) : if j in c_index: matrix[i][j] = 0
classSolution: defspiralOrder(self, matrix: List[List[int]]) -> List[int]: ans = [] i,j = 0,0 down = len(matrix) right = len(matrix[0]) total = down * right left = 1 up = 1 di,dj = 0,1 cnt = 0 if right == 1 : ans = [ i[0] for i in matrix ] return ans whileTrue : print(i,j) ans.append(matrix[i][j]) cnt += 1 if cnt == total : break i,j = i+di,j+dj if j == right-1and di == 0and dj == 1 : di,dj = 1,0 up = up + 1 if i == down-1and di == 1and dj == 0 : di,dj = 0,-1 right = right - 1 if j == left - 1and di == 0and dj == -1 : di,dj = -1,0 down = down - 1 if i == up - 1and di == -1and dj == 0 : di,dj = 0,1 left = left + 1 return ans
classSolution: defsearchMatrix(self, matrix: List[List[int]], target: int) -> bool: maxColIndex = len(matrix[0])-1 for i,n inenumerate(matrix[0]) : if n >= target : maxColIndex = i-1 if n == target : returnTrue print(maxColIndex) for i inrange(0,maxColIndex+1): for j inrange(len(matrix)) : if matrix[j][i] == target : returnTrue if matrix[j][i] > target : break returnFalse
思路二:二分查找
1 2 3 4 5 6 7 8 9
classSolution: defsearchMatrix(self, matrix: List[List[int]], target: int) -> bool: for row in matrix: if row[0] > target : break idx = bisect.bisect_left(row, target) if idx < len(row) and row[idx] == target: returnTrue returnFalse
# 递归 classSolution: # reverse head 后面的 包括head defr(self,head) : # print(head) # tail = head # while tail.next!=None : # tail = tail.next if head.next : self.r(head.next) head.next.next = head head.next = None # print(tail) defreverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: if head == None : return tail = head while tail.next!=None : tail = tail.next self.r(head) return tail
思路二:迭代*:
找到head开头的链的末端 往前指 前一个指空 (这是一个的垃圾方法),好好理理下面的那个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
# 不用看这个 复杂度不对 classSolution: defreverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: tail = head if head isNone : return while tail.next : tail = tail.next while head.next : # 找head的tail p = head pre = None while p.next : pre = p p = p.next else : p.next = pre pre.next = None return tail
这个时间复杂度很高 应该换一个,逐步对每个都处理:
1 2 3 4 5 6 7 8 9
classSolution: defreverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: prev, p = None, head while p : n = p.next p.next = prev prev = p p = n return prev
classSolution: defisPalindrome(self, head: Optional[ListNode]) -> bool: # 先统计长度 然后用栈 判断 stack = [] p, l = head, 0 while p : p = p.next l += 1 if l == 1 : returnTrue mid = l//2 isJumpMid = Trueif l%2 == 1elseFalse i, p = 1, head while p : if i <= mid : stack.append(p.val) else : if stack.pop() != p.val : returnFalse if i == mid and isJumpMid : i+=1 p = p.next i+=1 if p : p = p.next returnTrue
# 判断是否回文 result = True first_position = head second_position = second_half_start while result and second_position isnotNone: if first_position.val != second_position.val: result = False first_position = first_position.next second_position = second_position.next
# 还原链表并返回结果 first_half_end.next = self.reverse_list(second_half_start) return result
defend_of_first_half(self, head): fast = head slow = head while fast.nextisnotNoneand fast.next.nextisnotNone: fast = fast.next.next slow = slow.next return slow
defreverse_list(self, head): previous = None current = head while current isnotNone: next_node = current.next current.next = previous previous = current current = next_node return previous
classSolution: defhasCycle(self, head: Optional[ListNode]) -> bool: visited = set() while head : if head in visited : returnTrue visited.add(head) head = head.next returnFalse
# 快慢指针 classSolution: defhasCycle(self, head: Optional[ListNode]) -> bool: slow, fast = head, head ifnot head : returnFalse while slow and fast : slow = slow.next fast = fast.next.nextif fast.nextand fast.next.nextelseNone if slow == fast and slow : returnTrue returnFalse
我的判断逻辑写得不好,可以学一下别人的:
1 2 3 4 5 6 7 8 9
classSolution: defhasCycle(self, head: Optional[ListNode]) -> bool: slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: returnTrue returnFalse
classSolution: defremoveNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: slow = fast = head preSlow = None while n : fast = fast.next n -= 1 while fast : fast = fast.next preSlow = slow slow = slow.next ifnot preSlow : return head.next preSlow.next = slow.next return head
classSolution: defswapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: prev, ptr = None, head ans = head.nextif head and head.nextelse head flag = 0 while ptr : if flag < 1 : if prev : prev.next = ptr.nextif ptr.nextelse ptr prev = ptr ptr = ptr.next flag += 1 continue flag = 0 n = ptr.next ptr.next = prev prev.next = n ptr = n return ans
classSolution: # 反转k个 defreverseKOnce(self, head) : tail = head prev = None while head : n = head.next head.next = prev prev = head head = n return prev,tail
defreverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: ans = prev_subtail = ListNode(0) if k == 1: return head n = None whileTrue : start = head sublen = 1 while head : head = head.next sublen += 1 if sublen == k and head : n = head.next head.next = None head = n break if head ornot n: subhead,subtail = self.reverseKOnce(start) prev_subtail.next = subhead prev_subtail = subtail ifnot n : break else : prev_subtail.next = start break return ans.next
classSolution: defcopyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]': if head isNone: returnNone
cur = head while cur: cur.next = Node(cur.val, cur.next) cur = cur.next.next cur = head while cur: if cur.random: cur.next.random = cur.random.next cur = cur.next.next cur = head.next while cur.next: cur.next = cur.next.next cur = cur.next
classSolution: defmerge(self, head1: Optional[ListNode], head2: Optional[ListNode]) : p = dummy = ListNode(-999) while head1 and head2 : if head1.val < head2.val : p.next = head1 head1 = head1.next else : p.next = head2 head2 = head2.next p = p.next if head1 : p.next = head1 if head2 : p.next = head2 return dummy.next
# start包括 end不包括 defsort(self,start ,end) : ifnot start : return start if start.next == end : start.next = None return start fast = slow = start while fast != end : slow = slow.next fast = fast.next if fast != end : fast = fast.next mid = slow return self.merge(self.sort(start,mid),self.sort(mid,end))
classSolution: defmergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: # val,node minHeapNode = [] for i, n inenumerate(lists) : if n : minHeapNode.append((n.val,i,n)) heapq.heapify(minHeapNode) p = dummy = ListNode(0) i = len(lists) while minHeapNode : # print(minHeapNode) top = heapq.heappop(minHeapNode)[2] p.next = top p = p.next if top.next : heapq.heappush(minHeapNode,(top.next.val,i,top.next)) i += 1 return dummy.next
defprint(self,str) : p = self.dummyStart print(f'{str}',end=' ') while p : print(f'({p.key}-{p.value})',end=' ') p = p.next print(f'used:{self.used}/{self.capacity}')
classNode : def__init__(self, key=0, value=0, next=None, prev=None) : self.value = value self.key = key self.next = next self.prev = prev
classSolution: defmaxDepth(self, root: Optional[TreeNode]) -> int: ans = 0 que = [root] next_que = [] ifnot root : return0 while que : node = que[0] que.remove(node) if node.left : next_que.append(node.left) if node.right : next_que.append(node.right) ifnot que : ans += 1 que = next_que next_que = [] return ans
classSolution: defdigui(self,left,right): ifnot left andnot right : returnTrue if left and right and left.val == right.val : returnTrue & self.digui(left.left,right.right) & self.digui(left.right,right.left) else : returnFalse defisSymmetric(self, root: Optional[TreeNode]) -> bool: return self.digui(root,root)
classSolution: deflevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: ifnot root : return [] que = deque([root]) next_que = [] ans = [] while que : ans.append([]) while que : cur = que.popleft() ifnot cur : continue ans[-1].append(cur.val) if cur.left : next_que.append(cur.left) if cur.right : next_que.append(cur.right) que = deque(next_que) next_que = [] return ans
defisValidBST(self, root: Optional[TreeNode]) -> bool: self.nums = [] deffront(root): ifnot root : return if root.left : front(root.left) self.nums.append(root.val) if root.right : front(root.right) front(root) p = -999999999999 for n in self.nums : if p >= n : returnFalse p = n returnTrue
# BFS 找到最后一个 classSolution: defrightSideView(self, root: Optional[TreeNode]) -> List[int]: que = deque([root]) next_que = [] ans = [] ifnot root : return [] while que : ans.append(que[-1].val) while que : cur = que.popleft() ifnot cur : continue if cur.left : next_que.append(cur.left) if cur.right: next_que.append(cur.right) que = deque(next_que) next_que = [] return ans
classSolution: defflatten(self, root: Optional[TreeNode]) -> None: """ Do not return anything, modify root in-place instead. """ ifnot root : return dummy = TreeNode(0,None,None) ptr = dummy stk = [root] while stk : cur = stk.pop() ifnot cur : continue ptr.right = TreeNode(cur.val,None,None) ptr = ptr.right # print(cur.val,end='') stk.append(cur.right) stk.append(cur.left)
root.right = dummy.right.right root.left = None
思路一:存下来prev
因为cur已经被访问过了所以可以修改了,prev执指向现在cur 就可以修改其左右叶子值了
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defflatten(self, root: Optional[TreeNode]) -> None: """ Do not return anything, modify root in-place instead. """ stack = [root] if root else [] prev = None while stack: cur = stack.pop() if prev: prev.left, prev.right = None, cur if cur.right: stack.append(cur.right) if cur.left: stack.append(cur.left) prev = cur
classSolution: defbuildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: if preorder == [] : returnNone # for i,n in enumerate(inorder) : # if n == preorder[0] : # break i = inorder.index(preorder[0]) left_inorder = inorder[0:i] right_inorder = inorder[i+1:] # 可以知道 i 左右的数量 left_preorder = preorder[1:i+1] # for x in preorder : # if x in left_inorder : # left_preorder.append(x) right_preorder = preorder[i+1:] # for x in preorder : # if x in right_inorder : # right_preorder.append(x) # print(left_preorder,right_preorder) return TreeNode(preorder[0],self.buildTree(left_preorder,left_inorder),self.buildTree(right_preorder,right_inorder))
root = TreeNode(preorder[0]) stack = [root] inorderIndex = 0 for i inrange(1, len(preorder)): preorderVal = preorder[i] node = stack[-1] if node.val != inorder[inorderIndex]: node.left = TreeNode(preorderVal) stack.append(node.left) else: while stack and stack[-1].val == inorder[inorderIndex]: node = stack.pop() inorderIndex += 1 node.right = TreeNode(preorderVal) stack.append(node.right)
return root
Trash:递归拆分先序nums时候超时
答案对但是超时了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defbuildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: if preorder == [] : returnNone for i,n inenumerate(inorder) : if n == preorder[0] : break left_inorder = inorder[0:i] right_inorder = inorder[i+1:] left_preorder = [] for x in preorder : if x in left_inorder : left_preorder.append(x) right_preorder = [] for x in preorder : if x in right_inorder : right_preorder.append(x) # print(left_preorder,right_preorder) return TreeNode(preorder[0],self.buildTree(left_preorder,left_inorder),self.buildTree(right_preorder,right_inorder))
classSolution: defmaxPathSum(self, root: Optional[TreeNode]) -> int: res = -inf deffindmax(root): ifnot root: return0 nonlocal res left = findmax(root.left) if left < 0: left = 0 right = findmax(root.right) if right < 0: right = 0 if left + right + root.val > res: res = left + right + root.val returnmax(left,right) + root.val findmax(root) return res
classSolution: defnumIslands(self, grid: List[List[str]]) -> int: defdfs(i,j): if i<0or i>=len(grid): return0 if j<0or j>=len(grid[0]): return0 if grid[i][j] != '1' : return0 grid[i][j] = '2' dfs(i-1,j) dfs(i+1,j) dfs(i,j-1) dfs(i,j+1) return1 ans = 0 for i inrange(len(grid)) : for j inrange(len(grid[0])) : ans += dfs(i,j) return ans
思路二:BFS 队列和栈 在入的时候就标记
发现一个问题:如果这么写的话会超时 因为同一个点多次入队。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: defnumIslands(self, grid: List[List[str]]) -> int: r = len(grid) c = len(grid[0]) ans = 0 for i inrange(r) : for j inrange(c) : if grid[i][j] == '1' : ans += 1 que = deque([(i,j)]) while que : row,col = que.popleft() grid[row][col] = '2' for x,y in [ (row-1,col), (row+1,col), (row,col-1), (row,col+1) ] : if0<=x<r and0<=y<c and grid[x][y]=='1' : que.append((x,y)) return ans
应该这样写才是对的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution: defnumIslands(self, grid: List[List[str]]) -> int: r = len(grid) c = len(grid[0]) ans = 0 for i inrange(r) : for j inrange(c) : if grid[i][j] == '1' : ans += 1 grid[i][j] = '2' que = deque([(i,j)]) while que : row,col = que.popleft() # grid[row][col] = '2' for x,y in [ (row-1,col), (row+1,col), (row,col-1), (row,col+1) ] : if0<=x<r and0<=y<c and grid[x][y]=='1' : que.append((x,y)) grid[x][y] = '2' return ans
classSolution: deforangesRotting(self, grid: List[List[int]]) -> int: r = len(grid) c = len(grid[0]) defBFS(que: List): time = 0 ifnot que : return0 que = deque(que) next_que = [] while que : row,col = que.popleft() for x,y in [ (row+1,col), (row-1,col), (row,col+1), (row,col-1) ] : if0<=x<r and0<=y<c and grid[x][y] == 1 : next_que.append((x,y)) grid[x][y] = 2 ifnot que : time += 1 print(time, next_que) que = deque(next_que) next_que = [] return time-1 start = [] for i inrange(r) : for j inrange(c) : if grid[i][j] == 2 : start.append((i,j)) ans = BFS(start) for i inrange(r) : for j inrange(c) : if grid[i][j] == 1 : return -1 return ans
classSolution: deforangesRotting(self, grid: List[List[int]]) -> int: r = len(grid) c = len(grid[0]) mp = defaultdict(int) g = copy.deepcopy(grid) defBFS(i,j,grid) : time = 1 que = deque([(i,j)]) mp[(i,j)] = 0 next_que = [] while que : row,col = que.popleft() for x,y in [ (row-1,col), (row+1,col), (row,col-1), (row,col+1) ] : if0<=x<r and0<=y<c and (grid[x][y]==1) : next_que.append((x,y)) grid[x][y] = 2 mp[(x,y)] = min(time,mp[(x,y)]) if mp[(x,y)] != 0else time # print(mp[(x,y)]) ifnot que : que = deque(next_que) next_que = [] time += 1 return time ans = 0 flag = False for i inrange(r) : for j inrange(c) : if grid[i][j] == 2 : g = copy.deepcopy(grid) ans = max(BFS(i,j,g),ans) # print(mp) for i inrange(r) : for j inrange(c) : if grid[i][j] == 1and (i,j) notin mp.keys() : return -1 returnmax(mp.values()) if mp.values() else0
classSolution: defcanFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: mp = {} for l in prerequisites : if l[0] in mp.keys() : mp[l[0]].append(l[1]) else : mp[l[0]] = [l[1]] # 判断哈希表中有没有环
思路一:DFS
拓扑排序 省去了排序 只判断环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defcanFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: status = [0] * numCourses mp = defaultdict(list) for i in prerequisites : mp[i[0]].append(i[1]) defdfs(u: int): status[u] = 1 for v in mp[u]: if status[v] == 0 : if dfs(v) : returnTrue elif status[v] == 1 : # 有环 returnTrue status[u] = 2 for i inrange(numCourses) : if dfs(i) : returnFalse returnTrue
defDigui(nums): ans = [] iflen(nums) == 1 : return [[nums[0]]] for i inrange(len(nums)) : cp = nums[:] t = cp[0] cp[0] = cp[i] cp[i] = t sub_ans = Digui(cp[1:]) for b in sub_ans : a = [cp[0]] + b ans.append(a) return ans
defDigui(nums) : print(nums) iflen(nums)==1 : return [nums,[]] sub_ans = Digui(nums[1:]) ans = sub_ans[:] # print(sub_ans) for s in sub_ans : a = [nums[0]] + s print(f'-- {a}{[nums[0]]}{s}') ans.append(a) # print(ans) return ans
defDigui(str): index,remain = c2i(str[0]),str[1:] wl = mp[index] iflen(remain) == 0 : return wl sub_ans = Digui(remain) ans = [] for sub in sub_ans : for c in wl : ans.append(c+sub) return ans
classSolution: @lru_cache(None) defgenerateParenthesis(self, n: int) -> List[str]: if n == 0: return [''] ans = [] for c inrange(n): for left in self.generateParenthesis(c): for right in self.generateParenthesis(n-1-c): ans.append('({}){}'.format(left, right)) return ans
defcheck(i: int, j: int, k: int) -> bool: if board[i][j] != word[k]: returnFalse if k == len(word) - 1: returnTrue visited.add((i, j)) result = False for di, dj in directions: newi, newj = i + di, j + dj if0 <= newi < len(board) and0 <= newj < len(board[0]): if (newi, newj) notin visited: if check(newi, newj, k + 1): result = True break visited.remove((i, j)) return result
h, w = len(board), len(board[0]) visited = set() for i inrange(h): for j inrange(w): if check(i, j, 0): returnTrue returnFalse
classSolution: defexist(self, board: List[List[str]], word: str) -> bool: defdfs(i,j,target): if board[i][j] != target[0] : returnFalse iflen(target) == 1 : returnTrue res = False t, board[i][j] = board[i][j], '#' for (u,v) in [(0, 1), (0, -1), (1, 0), (-1, 0)] : u,v = i+u, j+v if0<=u<len(board) and0<=v<len(board[0]): if dfs(u,v,target[1:]) : res = True break board[i][j] = t return res ws = set(word) mp = defaultdict(int) for x inrange(len(board)) : for y inrange(len(board[0])) : if board[x][y] in ws : mp[board[x][y]] += 1 ifReverse = mp[word[0]] > mp[word[-1]] for c in word : mp[c]-=1 if mp[c]<0 : returnFalse word = word[::-1] if ifReverse else word[:] for x inrange(len(board)) : for y inrange(len(board[0])) : if board[x][y] == word[0] and dfs(x,y,word) : returnTrue returnFalse
classSolution: defexist(self, board: List[List[str]], word: str) -> bool: defdfs(i,j,target): if board[i][j] != target[0] : returnFalse iflen(target) == 1 : returnTrue res = False t, board[i][j] = board[i][j], '#' for (u,v) in [(0, 1), (0, -1), (1, 0), (-1, 0)] : u,v = i+u, j+v if0<=u<len(board) and0<=v<len(board[0]): if dfs(u,v,target[1:]) : res = True break board[i][j] = t return res ws = set(word) mp = defaultdict(int) for x inrange(len(board)) : for y inrange(len(board[0])) : if board[x][y] in ws : mp[board[x][y]] += 1 min_=100 start = 0 for i inrange(len(word)-1): sum_ = mp[word[i]] + mp[word[i+1]] if sum_ < min_ : min_ = sum_ start = i
for c in word : mp[c]-=1 if mp[c]<0 : returnFalse target1 = word[0:start] if word[0:start] else' ' target2 = word[start:] if word[start:] else' ' target1 = target1[::-1]
ans1 = set() ans2 = set() for x inrange(len(board)) : for y inrange(len(board[0])) : if board[x][y] == target1[0] and dfs(x,y,target1) : ans1.add((x,y)) if board[x][y] == target2[0] and dfs(x,y,target2) : ans2.add((x,y)) if start == 0or start == len(word)-1 : iflen(ans1) + len(ans2) != 0 : returnTrue ifnot (len(ans1) andlen(ans2)) : returnFalse for i,j in ans2 : ifany((i + dx, j + dy) in ans1 for dx, dy in [(0,1), (0,-1), (1,0), (-1,0)] ) : returnTrue returnFalse
classSolution: defsolveNQueens(self, n: int) -> List[List[str]]: col = set() diag_add = set() diag_mns = set() # 找到 第row行 Q可以放在哪 deftuple2board(tl): res = [] for i,j in tl : t = ['.'] * n t[j] = 'Q' res.append(''.join(t)) ans.append(res)
defdfs(row): if row == n : tuple2board(tuple_ans) return for i inrange(n) : if i in col or (row+i) in diag_add or (row-i) in diag_mns : continue col.add(i) diag_add.add(row+i) diag_mns.add(row-i) tuple_ans.append((row,i)) dfs(row+1) tuple_ans.pop() col.remove(i) diag_add.remove(row+i) diag_mns.remove(row-i) tuple_ans = [] ans = [] dfs(0) return ans
classSolution: defsearchInsert(self, nums: List[int], target: int) -> int: defbs(nl,tar): l = len(nl) if l == 0 : return0 mid = l//2 if nl[mid] == tar : return mid if nl[mid] > tar : res = bs(nl[:mid],tar) return res if nl[mid] < tar : res = bs(nl[mid+1:],tar) # 我觉得这个比较关键, 找后部分的数组时候要把现在的 mid 给存下来 # 还有一种方法是 直接用 left right 去找 return mid + res + 1 return bs(nums,target)
用left rihgt 写的 bs 这个是 闭闭区间
1 2 3 4 5 6 7 8 9 10 11 12
classSolution: defsearchInsert(self, nums: List[int], target: int) -> int: left, right = 0, len(nums) - 1 while left <= right: mid = (left + right) // 2 if target > nums[mid]: left = mid + 1 else: right = mid - 1 return left
classSolution: defsearchMatrix(self, matrix: List[List[int]], target: int) -> bool: # 先找到在哪一行,up down 是个 闭开区间 up, down = 0, len(matrix) while up < down : mid = (up+down)//2 if matrix[mid][0] == target : returnTrue if matrix[mid][0] > target : down = mid if matrix[mid][0] < target : up = mid + 1 nums=matrix[up-1][:] up, down = 0, len(nums) while up < down : mid = (up+down)//2 if nums[mid] == target : returnTrue if nums[mid] > target : down = mid if nums[mid] < target : up = mid + 1 returnFalse
classSolution: defsearchRange(self, nums: List[int], target: int) -> List[int]: # 找到的是 左到右 第一个大于或等于 target 的 index defbs(nums_list,tar) : # print(nums_list,tar) left, right = 0, len(nums_list) while left < right : mid = (left+right)//2 if nums_list[mid] < tar : left = mid + 1 if nums_list[mid] >= tar : right = mid return left ifnot nums : return [ -1, -1 ] start = bs(nums,target) if start >= len(nums) or nums[start] != target : return [ -1, -1 ] return [ start, bs(nums,target+1)-1 ]
但是这样要两次 bs ,(而且我好像发现 二分搜索 闭闭区间 好像更好写)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
deffindlowerindex(nums: List[int], target: int)-> int: left = 0 right = len(nums)-1 while left<=right: mid = (left + right )//2 if nums[mid]<target: left = mid+1 else: right = mid-1 return left
classSolution: defsearchRange(self, nums: List[int], target: int) -> List[int]: if findlowerindex(nums,target)==len(nums) or nums[findlowerindex(nums,target)] != target: return [-1,-1] return[findlowerindex(nums, target),findlowerindex(nums, target+1)-1]
classSolution: # 153. 寻找旋转排序数组中的最小值(返回的是下标) deffindMin(self, nums: List[int]) -> int: left, right = 0, len(nums) - 1 while left < right: mid = (left + right) // 2 if nums[mid] < nums[right]: right = mid else: left = mid + 1 return right
# 有序数组中找 target 的下标 deflower_bound(self, nums: List[int], left: int, right: int, target: int) -> int: while left + 1 < right: # 开区间不为空 mid = (left + right) // 2 # 循环不变量: # nums[right] >= target # nums[left] < target if nums[mid] >= target: right = mid # 范围缩小到 (left, mid) else: left = mid # 范围缩小到 (mid, right) return right if nums[right] == target else -1
defsearch(self, nums: List[int], target: int) -> int: i = self.findMin(nums) if target > nums[-1]: # target 在第一段 return self.lower_bound(nums, -1, i, target) # 开区间 (-1, i) # target 在第二段 return self.lower_bound(nums, i - 1, len(nums), target) # 开区间 (i-1, n)
思路二:一次bs 这个我还没看懂
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defsearch(self, nums: List[int], target: int) -> int: n = len(nums) l, r = 0, n - 1 while l < r: mid = (l + r) // 2 x = nums[mid] if x >= nums[0] and (target > x or target < nums[0]): l = mid + 1 elif x < target < nums[0]: l = mid + 1 else: r = mid return -1if nums[r] != target else r
classSolution: deffindMin(self, nums: List[int]) -> int: left, right = 0, len(nums)-1 while left < right : mid = (left+right)//2 if nums[mid] < nums[right] : right = mid else : left = mid + 1 # print(left,right) return nums[left]
1 2 3 4 5 6 7 8 9 10 11
classSolution: deffindMin(self,nums): left, right = 0, len(nums)-1 while left < right : mid = (left+right)//2 if nums[mid] <= nums[right] : right = mid else : left = mid + 1 print(left,right) return nums[left]
classSolution: deffindMedianSortedArrays(self, a: List[int], b: List[int]) -> float: iflen(a) > len(b): a, b = b, a
m, n = len(a), len(b) # 循环不变量:a[left] <= b[j+1] # 循环不变量:a[right] > b[j+1] left, right = -1, m while left + 1 < right: # 开区间 (left, right) 不为空 i = (left + right) // 2 j = (m + n - 3) // 2 - i if a[i] <= b[j + 1]: left = i # 缩小二分区间为 (i, right) else: right = i # 缩小二分区间为 (left, i)
# 此时 left 等于 right-1 # a[left] <= b[j+1] 且 a[right] > b[j'+1] = b[j],所以答案是 i=left i = left j = (m + n - 3) // 2 - i ai = a[i] if i >= 0else -inf bj = b[j] if j >= 0else -inf ai1 = a[i + 1] if i + 1 < m else inf bj1 = b[j + 1] if j + 1 < n else inf max1 = max(ai, bj) min2 = min(ai1, bj1) return max1 if (m + n) % 2else (max1 + min2) / 2
遇到 [ 时候 :记录 重复次数,处理到当前之前的字符结果,并把这个临时结果 res 置为 空
遇到 ] 时候 :弹栈 此时 两个括号内的内容 在 res 中,然后括号前的内容在栈顶,拼接即可 得到新的 res
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defdecodeString(self, s: str) -> str: stack, res, multi = [], "", 0 for c in s: if c == '[': stack.append([multi, res]) res, multi = "", 0 elif c == ']': cur_multi, last_res = stack.pop() res = last_res + cur_multi * res elif'0' <= c <= '9': multi = multi * 10 + int(c) else: res += c return res
思路二:递归
递归处理括号内的字符串,遇到括号就dfs 传入的 位置 i 标记了 这个括号内字符串的开始,感觉和上面的本质上没有区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defdecodeString(self, s: str) -> str: defdfs(s, i): res, multi = "", 0 while i < len(s): if'0' <= s[i] <= '9': multi = multi * 10 + int(s[i]) elif s[i] == '[': i, tmp = dfs(s, i + 1) res += multi * tmp multi = 0 elif s[i] == ']': return i, res else: res += s[i] i += 1 return res return dfs(s,0)
classSolution: # 用这个例子想一下 # 4 5 6 2 0 3 7 4 # 1 1 4 2 1 1 0 0 defdailyTemperatures(self, t: List[int]) -> List[int]: # 单调递减栈,记录index,被弹走时计算 index差值 最后留在stk中的就是 0 用 0 初始化 stk = [0] ans = [0] * len(t) for i inrange(1,len(t)) : while stk and t[i] > t[stk[-1]] : index = stk.pop() ans[index] = i - index stk.append(i) return ans
思路二:别的写的另一种方法 暂时没仔细看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution: defdailyTemperatures(self, temperatures: List[int]) -> List[int]: n = len(temperatures) hottest = 0 answer = [0] * n for curr_day inrange(n - 1, -1, -1): current_temp = temperatures[curr_day] if current_temp >= hottest: hottest = current_temp continue # [73,74,75,71,69,72,76,73] days = 1 while temperatures[curr_day + days] <= current_temp: # Use information from answer to search for the next warmer day days += answer[curr_day + days] answer[curr_day] = days
# 单调栈 对每根柱子h找到 第一个 小于h 的 前一个就是边界 classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: # 类似温度的方法 记录 下一个小于他的位置 defnextLess(nums): stk = [] res = [ 0 ] * len(nums) for i inrange(len(nums)): while stk and nums[stk[-1]] > nums[i] : top = stk.pop() res[top] = i-top stk.append(i) return res ans = 0 right = nextLess(heights) left = nextLess(heights[::-1])[::-1] for i inrange(len(heights)) : r = i+right[i]-1if right[i] != 0elselen(heights)-1 l = i-left[i]+1if left[i] != 0else0 ans = max( (r-l+1)*heights[i] , ans ) return ans
下面这个代码是 找 每个元素 左边 第一个小于他的,维护 单调递增栈 出站不更新,入栈之前更新。 上面的写法是找右边第一个小/大于他的,是在 pop 时候更新。
1 2 3 4 5 6 7
for i,n inenumerate(heights) : top = 0 while stk and heights[stk[-1]] > n : top = stk.pop() res[i] = i - stk[-1] if stk else0 stk.append(i) print(res)
但是这个算法的复杂度虽然是 但是 速度还是比较慢 遍历了三次数组 ,下面用一次遍历解决问题
思路二:单调栈+优化 (最优
既然入栈确定左边界 出栈确定右边界 能不能一次确定h的两个边界
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution: # 对一个 H # 找到 右边 第一个比他小的 (pop后更新) 单调递增栈 # 找到 左边 第一个比他小的 (append前更新) 单调递增栈 deflargestRectangleArea(self, heights: List[int]) -> int: # 维护单调递增栈 保证每个元素都能出入栈 heights = [0]+heights+[0] stk = [] left, right = [0]*len(heights),[0]*len(heights) for i,n inenumerate(heights) : while stk and n <= heights[stk[-1]] : top = stk.pop() right[top] = i left[i] = stk[-1] if stk else0 stk.append(i) returnmax((right[i]-left[i]-1)*heights[i] for i inrange(len(heights)))
这个优化 还是要遍历两次,遍历一次的是:(*********这个没自己写过)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: # heights前面补上零,原因是单个柱子也可以拿出来计算 # 同时在末尾也加上零,否则无法触发剩余在栈中元素的计算 heights.insert(0, 0) heights.append(0) stack = [0] res = 0 for i inrange(1, len(heights)): h = heights[i] if stack and h == heights[stack[-1]]: stack.pop() else: while stack and h < heights[stack[-1]]: mid = stack.pop() l, r = stack[-1], i res = max(res, heights[mid] * (r - l - 1)) stack.append(i) return res
超时
遍历index
1 2 3 4 5 6 7 8 9
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: ans = 0 l = len(heights) for i inrange(l): for j inrange(i,l): S = min(heights[i:j+1])*(j-i+1) ans = max(ans,S) return ans
遍历高度:遍历高度 h 为什么能找到最优解?是因为这种方法找到了 最小值为 h,也就是高度为 h 能组成的最大矩形。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# 遍历高 classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: ans = 0 l = len(heights) for i inrange(l): h = heights[i] left, right = i, i while left > 0and heights[left-1] >= h : left -= 1 while right < l-1and heights[right+1] >= h : right += 1 S = h*(right-left+1) print(left,right,h,S) ans = max(S,ans) return ans
classSolution: deftopKFrequent(self, nums: List[int], k: int) -> List[int]: KK = k cnt = defaultdict(int) for n in nums : cnt[n] += 1 p = [] for k,v in cnt.items() : p.append((k,v)) p = sorted(p,key=lambda x: x[1],reverse=True) return [ p[i][0] for i inrange(KK) ]
思路二:堆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from typing importList from collections import Counter import heapq
classSolution: defmaxProfit(self, prices: List[int]) -> int: # 记录每个位置后面的最大值 t_max = prices[-1] ans = 0 for i inrange(len(prices)) : index = len(prices)-i-1 t_max = max(t_max,prices[index]) ans = max(t_max-prices[index],ans) return ans
不用max 只用 一次len 会加速速度 如果更新了最低价 就不需要 更新ans了
1 2 3 4 5 6 7 8
classSolution: defmaxProfit(self, prices: List[int]) -> int: # 记录每个位置之前的最小值 past_min, ans = +inf, 0 for p in prices : past_min = p if p < past_min else past_min ans = p-past_min if (p-past_min) > ans else ans return ans
classSolution: defjump(self, nums: List[int]) -> int: # 维护 跳到一个位置时候 能到的最大位置是多少 还是贪心 step, farest, end, l = 0, 0, 0, len(nums) if l == 1 :return0 for i inrange(l) : farest = max(nums[i] + i, farest) if i == end : end = farest step += 1 # print(step,end) # 几步最远可以跳到哪 if end >= l-1 : return step
Trash - 动态规划 但是不好
时间复杂度很高
1 2 3 4 5 6 7 8 9 10 11 12
classSolution: defjump(self, nums: List[int]) -> int: # 记录到达每个位置的 最小步数 l = len(nums) dp = [+inf] * l dp[0] = 0 for i inrange(l): for j inrange(1,nums[i]+1) : if i+j == l : break dp[i+j] = min(dp[i+j],dp[i]+1) return dp[-1]
size = len(nums) if size == 1: return nums[0] first, second = nums[0], max(nums[0], nums[1]) for i inrange(2, size): first, second = second, max(first + nums[i], second) return second
classSolution: defwordBreak(self, s: str, wordDict: List[str]) -> bool: #如果就不存在的字母直接 False WW = '' for w in wordDict : WW+=w charSet = set(WW) for c in s: if c notin charSet : returnFalse
# 到index 为止(包括) 能不能被组成 dp = [False] * (len(s)+1) dp[0] = True wordDict = set(wordDict) wordlenlist = set() for w in wordDict : wordlenlist.add(len(w)) wordlenlist = sorted(list(wordlenlist)) print(wordlenlist) lastTrue = [0] que = deque([0]) while que : index = que.popleft() for l in wordlenlist : if index+l > len(s) : break if s[index:index+l] in wordDict : dp[index+l] = True que.append(index+l) print(dp) return dp[-1]
思路二:BFS 题解的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defwordBreak(self, s: str, wordDict: List[str]) -> bool: max_len = max(map(len, wordDict)) # 用于限制下面 j 的循环次数 words = set(wordDict) # 便于快速判断 s[j:i] in words
@cache # 缓存装饰器,避免重复计算 dfs 的结果(记忆化) defdfs(i: int) -> bool: if i == 0: # 成功拆分! returnTrue for j inrange(i - 1, max(i - max_len - 1, -1), -1): if s[j:i] in words and dfs(j): returnTrue returnFalse
#贪心算法,为了让子序列尽可能长,所以就选择尽可能小的值组成上升序列,然后得到尽可能长的上升序列。 classSolution: deflengthOfLIS(self, nums: List[int]) -> int: # 用 dp 维护一个 dp[i] 表示 **长度为 i 的最长上升子序列的末尾元素的最小值** dp 并不直接是一个子序列注意定义 d = [] for n in nums: # 如果这个数能构成上升序列就加进来 ifnot d or n > d[-1]: d.append(n) # 若构成不了,也要把这个数换进来,用二分查找 找该换到的位置。(为了保证数组尽量上升的慢)更新的是len为 mid 结尾的最小元素 else: l, r = 0, len(d) - 1 loc = r while l <= r: mid = (l + r) // 2 if d[mid] >= n: loc = mid r = mid - 1 else: l = mid + 1 d[loc] = n print(n,d) returnlen(d)
classSolution: defcanPartition(self, nums: List[int]) -> bool: target = sum(nums)/2 if target%1!=0 : returnFalse mp = defaultdict(int) mp[int(target)] = 1 for n in nums: ks = list(mp.keys()) for k in ks: if k==n : returnTrue if k-n > 0 : mp[k-n]+=1 mp[target-n]+=1 returnFalse
classSolution: defcanPartition(self, nums: List[int]) -> bool: #sumV = sum(nums) # can I find a subset of integers which can # summ to sumV/2 s = sum(nums) if s % 2 == 1: returnFalse half = s//2 defsubSum(currSum,i): if i < 0: returnFalse if currSum + nums[i] == half: returnTrue if currSum + nums[i] < half: if subSum(currSum+ nums[i],i-1): returnTrue else: return subSum(currSum,i-1) return subSum(0,len(nums)-1)
classSolution: defcanPartition(self, nums: List[int]) -> bool: s = sum(nums) if s%2:returnFalse bit = 1 target = s //2 for x in nums: bit |= (bit << x) return (bit >> target) & 1 == 1
# @cache # def dfs(i, cur): # if i < 0: # return False # #这项选还是不选 # if cur == target: # return True # else: # return dfs(i-1, cur + nums[i]) or dfs(i-1, cur) return dfs(n-1, 0)
classSolution: defminPathSum(self, grid: List[List[int]]) -> int: # dp到达某个点的最短距离 for r inrange(1,len(grid)): grid[r][0] += grid[r-1][0] for c inrange(1,len(grid[0])): grid[0][c] += grid[0][c-1] for r inrange(1,len(grid)) : for c inrange(1,len(grid[0])) : grid[r][c] += min(grid[r-1][c],grid[r][c-1]) return grid[-1][-1]
classSolution: deflongestPalindrome(self, s: str) -> str: # dp 以 i 为结尾的最长子序列 这个难以实现 试试 i,j 是否构成 回文串 l = len(s) isPal = set() for i inrange(l) : isPal.add((i,i)) isPal.add((i+1,i)) # cbbd 这种 ans = s[0] # ij 是不是 依赖 i+1 j-1 画个i*j图 确定遍历顺序 for j inrange(l) : for i inrange(j,-1,-1): if (i+1,j-1) in isPal and s[i]==s[j] : isPal.add((i,j)) ans = s[i:j+1] if j-i+1 > len(ans) else ans return ans
classSolution: defexpand(self, s, left, right): """中心扩展算法,计算当前节点的臂长""" while left >= 0and right < len(s) and s[left] == s[right]: left -= 1 right += 1 return (right - left - 2) // 2
# 2.遍历回文中心 for i inrange(len(s)): # 3.如果此时遍历的中心点已经超过了最远的有边界位置 if i > right: cur_arm_len = self.expand(s, i, i) # 4.如果还没超过 else: # 4.1计算对称点 i_sym = 2*j - i # 4.2计算开始遍历的臂长 min_arm_len = min(arm_len[i_sym], right - i) # 4.3更新臂长 cur_arm_len = self.expand(s, i - min_arm_len, i + min_arm_len) # 5.记录当前位置的臂长 arm_len.append(cur_arm_len) # 6.如果当前臂长超过了最长记录,更新状态 if i + cur_arm_len > right: right = i + cur_arm_len j = i # 7.如果长度大于输出的结果 if2 * cur_arm_len + 1> end - start: start = i - cur_arm_len end = i + cur_arm_len # 8.切片输出跳过# return s[start + 1: end + 1 : 2]
最好*:别人写的中心拓展
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: deflongestPalindrome(self, s: str) -> str: n = len(s) ans_left = ans_right = 0 #奇数长度回文的中心:n 个,偶数中心:n-1个;总共:n + (n-1) = 2n - 1 个中心 for i inrange(2*n-1): l,r = i//2, (i+1)//2#通过整数除法处理奇偶中心 while l >= 0and r < n and s[l] == s[r]: l -= 1 r += 1 if r - l - 1 > ans_right - ans_left: ans_left,ans_right = l+1, r return s[ans_left : ans_right]
classSolution: deflongestCommonSubsequence(self, text1: str, text2: str) -> int: # Step 1: Record positions of each character in text1 char_masks = {} for i, char inenumerate(text1): char_masks[char] = char_masks.get(char, 0) | (1 << i) # v stores the "increment" bits (1 if dp[j] > dp[j-1]) v = 0 for char in text2: # x marks all possible match positions OR existing increments x = char_masks.get(char, 0) | v # (v << 1) | 1 creates a "borrow" bit to start the chain reaction # x - (...) performs bit-parallel search for the first available '1' # x ^ (...) identifies which bits were affected by the subtraction # x & (...) picks the bits that actually contribute to the LCS increment v = x & (x ^ (x - ((v << 1) | 1))) return v.bit_count() # count_set_bits(v)
classSolution: defmajorityElement(self, nums: List[int]) -> int: mp = defaultdict(int) for n in nums : mp[n]+=1 for k,v in mp.items() : if v > len(nums)/2 : return k