classSolution: deftwoSum(self, nums: List[int], target: int) -> List[int]: d = {} for i, n inenumerate(nums): if n in d: return [d[n], i] d[target-n] = i
classSolution: deflongestPalindrome(self, s: str) -> str: r = '' for i, j in [(i, j) for i inrange(len(s)) for j in (0, 1)]: while i > -1and i + j < len(s) and s[i] == s[i + j]: i, j = i - 1, j + 2 r = max(r, s[i + 1:i + j], key=len) return''ifnot s else r
classSolution: defthreeSum(self, nums: List[int]) -> List[List[int]]: nums, r = sorted(nums), set() for i in [i for i inrange(len(nums)-2) if i < 1or nums[i] > nums[i-1]]: d = {-nums[i]-n: j for j, n inenumerate(nums[i + 1:])} r.update([(nums[i], n, -nums[i]-n) for j, n inenumerate(nums[i+1:]) if n in d and d[n] > j]) returnlist(map(list, r))
时间复杂度:$O(N^2)$
这里 sort 一是为了避免重复,这一点可以体现在我们输出的结果都是升序的,如果不这么做 set 无法排除一些相同结果,而是为了节省计算,防止超时
for 循环内部的代码思想同第一题 Two Sum,用字典记录{需要的值:当前索引},如果字典中存在相同的数字,那么将会记录比较大的那个索引,因此可以用d[n] > i来避免一个元素重复选择
classSolution: defthreeSumClosest(self, nums: List[int], target: int) -> int: nums, r, end = sorted(nums), float('inf'), len(nums) - 1 for c inrange(len(nums) - 2): i, j = max(c + 1, bisect.bisect_left(nums, target - nums[end] - nums[c], c + 1, end) - 1), end while r != target and i < j: s = nums[c] + nums[i] + nums[j] r, i, j = min(r, s, key=lambda x: abs(x - target)), i + (s < target), j - (s > target) return r
float('inf') = +∞(正无穷)
排序,遍历,双指针,$O(N^2)$ 时间复杂度,二分法初始化
排序是为了使用双指针,首先遍历得到索引 c,然后计算 c,左指针 i,右指针 j 对应数字之和,如果大于 target,j 向内移动,否则 i 向内移动
classSolution: defletterCombinations(self, digits: str) -> List[str]: from itertools import product l = '- - abc def ghi jkl mno pqrs tuv wxyz'.split() return [''.join(c) for c in product(*[l[int(i)] for i in digits])] if digits else []
classSolution: deffourSum(self, nums: List[int], target: int) -> List[List[int]]: from itertools import combinations as com dic, l = collections.defaultdict(list), [*com(range(len(nums)), 2)] for a, b in l: dic[target - nums[a] - nums[b]].append((a, b)) r = [(*ab, c, d) for c, d in l for ab in dic[nums[c] + nums[d]]] return [*set(tuple(sorted(nums[i] for i in t)) for t in r iflen(set(t)) == 4)]
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defremoveNthFromEnd(self, head: ListNode, n: int) -> ListNode: l = [] while head: l, head = l + [head], head.next if n != len(l): l[-n-1].next = l[-n].next del l[-n] return l and l[0]
classSolution: defisValid(self, s: str) -> bool: whileany(('()'in s, '[]'in s, '{}'in s)): s = s.replace('()', '').replace('[]', '').replace('{}', '') returnnot s
不断删除有效括号直到不能删除,思路简单效率低。另外,stack的方法也很简单,而且快多了。
1 2 3 4 5 6 7 8 9
classSolution: defisValid(self, s: str) -> bool: stack, d = [], {'{': '}', '[': ']', '(': ')'} for p in s: if p in'{[(': stack += [p]; elifnot (stack and d[stack.pop()] == p): returnFalse returnnot stack
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defmergeKLists(self, lists: List[ListNode]) -> ListNode: r, n, p = [], lists and lists.pop(), None while lists or n: r[len(r):], n = ([n], n.nextor lists and lists.pop()) if n else ([], lists.pop()) for n insorted(r, key=lambda x: x.val, reverse=True): n.next, p = p, n return n if r else []
本题思路:
把题目给的所有链表中的所有节点放进一个列表 r。
对这个列表 r 中的所有节点进行从大到小的排序。$O(N\log N)$
把每个节点的指针指向前一个节点。(第一个节点,也就是最大的那个,指向None。)
返回最后一个节点,也就是整个新链表的开头。
如何把所有节点放进 r(result link)?
我们首先初始化 r 为空列表,初始化 n(node) 为题目所给的第一个链表的开头节点,并删除lists中的这个节点,接着进入while循环,如果 n 不为空,那么 r += [n],这里使用了切片的技巧(r[len(r):]=[n]相当于r=r+[n]),n=n.next,如果n是第一个链表的最后一个节点的话n.next就是None,下一次while的时候如果lists不为空就说明还有别的链表,此时n为None,我们让 r 不变,n=lists.pop(),也就是从lists中再取下一个节点赋值给n,重复以上步骤直到 lists 为空,我们就把所有节点放进 r 了。
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defswapPairs(self, head: ListNode) -> ListNode: if head and head.next: head.next.next, head.next, head = head, self.swapPairs(head.next.next), head.next return head
classSolution: defdivide(self, dividend: int, divisor: int) -> int: a, b, r, t = abs(dividend), abs(divisor), 0, 1 while a >= b or t > 1: if a >= b: r += t; a -= b; t += t; b += b else: t >>= 1; b >>= 1 returnmin((-r, r)[dividend ^ divisor >= 0], (1 << 31) - 1)
让被除数不断减去除数,直到不够减。每次减完后除数翻倍,并记录当前为初始除数的几倍(用 t 表示倍数 time),若发现不够减且 t 不为 1 则让除数变为原来的一半, t 也减半
classSolution: defsearch(self, nums, target): lo, hi, k = 0, len(nums) - 1, -1 while lo <= hi: m = (lo + hi) // 2 if m == len(nums) - 1or nums[m] > nums[m+1]: k = m + 1 break elif m == 0or nums[m] < nums[m-1]: k = m break if nums[m] > nums[0]: lo = m + 1 else: hi = m - 1 i = (bisect.bisect_left(nums[k:] + nums[:k], target) + k) % max(len(nums), 1) return i if nums and nums[i] == target else -1
class Solution: def searchRange(self, nums: List[int], target: int) -> List[int]: # if not nums or target not in nums: return [-1, -1] return [bisect.bisect_left(nums, target), bisect.bisect_right(nums, target)-1] \ if nums and target in nums else [-1, -1]
classSolution: defisValidSudoku(self, board: List[List[str]]) -> bool: row = [[x for x in y if x != '.'] for y in board] col = [[x for x in y if x != '.'] for y inzip(*board)] pal = [[board[i+m][j+n] for m inrange(3) for n inrange(3) if board[i+m][j+n] != '.'] for i in (0, 3, 6) for j in (0, 3, 6)] returnall(len(set(x)) == len(x) for x in (*row, *col, *pal))
classSolution: defpermute(self, nums: List[int]) -> List[List[int]]: return [[n] + sub for i, n inenumerate(nums) for sub in self.permute(nums[:i] + nums[i+1:])] or [nums]
classSolution: defgenerateMatrix(self, n: int) -> List[List[int]]: r, n = [[n**2]], n**2 while n > 1: n, r = n - len(r), [[*range(n - len(r), n)]] + [*zip(*r[::-1])] return r
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defrotateRight(self, head: ListNode, k: int) -> ListNode: l = [] while head: l[len(l):], head = [head], head.next if l: l[-1].next, l[-1 - k % len(l)].next = l[0], None return l[- k % len(l)] if l elseNone
classSolution: defaddBinary(self, a: str, b: str) -> str: r, p = '', 0 d = len(b) - len(a) a = '0' * d + a b = '0' * -d + b for i, j inzip(a[::-1], b[::-1]): s = int(i) + int(j) + p r = str(s % 2) + r p = s // 2 return'1' + r if p else r
classSolution: defsimplifyPath(self, path: str) -> str: r = [] for s in path.split('/'): r = {'':r, '.':r, '..':r[:-1]}.get(s, r + [s]) return'/' + '/'.join(r)
classSolution: defsetZeroes(self, matrix: List[List[int]]) -> None: row = [[0] * len(i) if0in i else i for i in matrix] col = [[0] * len(j) if0in j elselist(j) for j inzip(*matrix)] col2row = list(map(list, zip(*col))) # 上面一行效果等同: # col2row = [list(i) for i in zip(*col)] for i inrange(len(matrix)): matrix[i] = col2row[i] if row[i] != [0] * len(matrix[0]) else row[i]
defremoveDuplicates(nums: [int]) -> int: for i inrange(len(nums)-3, -1, -1): if nums[i] == nums[i+1] and nums[i] == nums[i+2]: nums.pop(i) returnlen(nums)
classSolution: defmerge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: """ Do not return anything, modify nums1 in-place instead. """ while n > 0: nums1[m+n-1], m, n = (nums1[m-1], m-1, n) if m and nums1[m-1] > nums2[n-1] else (nums2[n-1], m, n-1)
这种题倒着算更容易
上面那行代码其实就相当于:
1 2 3 4 5 6 7 8 9 10
classSolution: defmerge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: """ Do not return anything, modify nums1 in-place instead. """ while n > 0: if m and nums1[m-1] > nums2[n-1]: nums1[m+n-1], m, n = nums1[m-1], m-1, n else: nums1[m+n-1], m, n = nums2[n - 1], m, n-1
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: defisValidBST(self, root: TreeNode, first=True) -> bool: ifnot root: return first or [] l = self.isValidBST(root.left, 0) + [root.val] + self.isValidBST(root.right, 0) returnall([a > b for a, b inzip(l[1:], l)]) if first else l
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: defhasPathSum(self, root: TreeNode, sum: int) -> bool: ifnot root: returnFalse l, r, f = root.left, root.right, lambda x: self.hasPathSum(x, sum - root.val) return l is r andsum == root.val or f(l) or f(r)
考虑初始状态:当树不存在时直接返回 False
考虑支路1:当前节点为叶节点时直接判断总和是否达到要求
考虑支路2:当前节点为非叶节点时将总和缩小并继续递归,判断左右节点是否存在满足条件的
当递归函数到达叶节点时,sum 已经被削减了多次,此时 sum - node.val 即为 原始的sum - 整条路径的总和
classSolution: defgenerate(self, numRows: int) -> List[List[int]]: return [[math.factorial(i)//math.factorial(i-j)//math.factorial(j) for j inrange(i+1)] for i inrange(numRows)]
classSolution: defgenerate(self, numRows: int) -> List[List[int]]: r = [[1]] for i inrange(1, numRows): r.append([1] + [sum(r[-1][j:j+2]) for j inrange(i)]) return numRows and r or []
classSolution: defwordBreak(self, s, wordDict): deff(s, d={}): ifnot s in d: for i inrange(1, 1 + len(s)): d[s[:i]] = s[:i] in wordDict and (i == len(s) or f(s[i:])) if d[s[:i]]: returnTrue returnFalse return d[s] return f(s)
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None
classSolution(object): defhasCycle(self, head): """ :type head: ListNode :rtype: bool """ while head and head.val != None: head.val, head = None, head.next return head != None
这题不支持python3,所以用pyhton2解法代替,下题记得调回来
破坏走过的所有节点,下次再遇到就知道了
不过以上方法会丢失原有信息,一般解法为快慢指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None
classSolution(object): defhasCycle(self, head): slow = fast = head while fast and fast.next: fast = fast.next.next slow = slow.next if slow == fast: returnTrue returnFalse
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None
classSolution(object): defdetectCycle(self, head): """ :type head: ListNode :rtype: ListNode """ s = {None} while head notin s: s.add(head) head = head.next return head
把见过的节点丢集合里,下次再遇见就是环的开始
还有一个纯数学的快慢指针解法,设环的起始节点为 E,快慢指针从 head 出发,快指针速度为 2,设相交节点为 X,head 到 E 的距离为 H,E 到 X 的距离为 D,环的长度为 L,那么有:快指针走过的距离等于慢指针走过的距离加快指针多走的距离(多走了 n 圈的 L) 2(H + D) = H + D + nL,因此可以推出 H = nL - D,这意味着如果我们让俩个慢指针一个从 head 出发,一个从 X 出发的话,他们一定会在节点 E 相遇
1 2 3 4 5
_____ / \ head___________E \ \ / X_____/
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution(object): defdetectCycle(self, head): slow = fast = head while fast and fast.next: fast = fast.next.next slow = slow.next if slow == fast: break else: returnNone while head isnot slow: head = head.next slow = slow.next return head
classSolution: defevalRPN(self, tokens: List[str]) -> int: t, f = tokens.pop(), self.evalRPN if t in'+-*/': b, a = f(tokens), f(tokens) t = eval('a' + t + 'b') returnint(t)
# Your MinStack object will be instantiated and called as such: # obj = MinStack() # obj.push(x) # obj.pop() # param_3 = obj.top() # param_4 = obj.getMin()
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None
classSolution(object): defgetIntersectionNode(self, headA, headB): """ :type head1, head1: ListNode :rtype: ListNode """ a, b = (headA, headB) if headA and headB else (None, None) while a != b: a, b = not a and headB or a.next, not b and headA or b.next return a
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defremoveElements(self, head: ListNode, val: int) -> ListNode: if head: head.next = self.removeElements(head.next, val) return head.nextif head and head.val == val else head
classSolution: deffindKthLargest(self, nums: List[int], k: int) -> int: l = [x for x in nums if x > nums[0]] m = [x for x in nums if x == nums[0]] r = [x for x in nums if x < nums[0]] f = self.findKthLargest
if k <= len(l): return f(l, k) elif k <= len(l) + len(m): return nums[0] return f(r, k - len(l) - len(m))
classSolution: defcontainsNearbyDuplicate(self, nums: List[int], k: int) -> bool: r, d = k + 1, {} for i, n inenumerate(nums): r, d[n] = min(r, i - d.get(n, -k - 1)), i return r <= k
def__init__(self): """ Initialize your data structure here. """ self.stack = []
defpush(self, x: int) -> None: """ Push element x to the back of queue. """ self.stack.append(x)
defpop(self) -> int: """ Removes the element from in front of queue and returns that element. """ temp = [] while self.stack: temp.append(self.stack.pop()) r = temp.pop() while temp: self.stack.append(temp.pop()) return r
defpeek(self) -> int: """ Get the front element. """ temp = [] while self.stack: temp.append(self.stack.pop()) r = temp[-1] while temp: self.stack.append(temp.pop()) return r
defempty(self) -> bool: """ Returns whether the queue is empty. """ returnnot self.stack
# Your MyQueue object will be instantiated and called as such: # obj = MyQueue() # obj.push(x) # param_2 = obj.pop() # param_3 = obj.peek() # param_4 = obj.empty()
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: deflowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': l, r = map(lambda x: x and self.lowestCommonAncestor(x, p, q), (root.left, root.right)) return (root in (p, q) or l and r) and root or l or r
classSolution: defproductExceptSelf(self, nums: List[int]) -> List[int]: res, l, r = [1] * len(nums), 1, 1 for i, j inzip(range(len(nums)), reversed(range(len(nums)))): res[i], l = res[i] * l, l * nums[i] res[j], r = res[j] * r, r * nums[j] return res
# The isBadVersion API is already defined for you. # @param version, an integer # @return a bool # def isBadVersion(version):
classSolution: deffirstBadVersion(self, n): """ :type n: int :rtype: int """ l, h = 1, n while l <= h: m = (l + h) // 2 if isBadVersion(m) > m * isBadVersion(m - 1): return m elif isBadVersion(m): h = m - 1 else: l = m + 1
本题二分搜索中判断返回的条件为 当前版本为True且(当前索引为0 或 左边的版本为False)
m * 的作用是避免 m - 1 为负数,如果 m 为 0,则代表左边没有版本,只需判断当前版本是否为 True
classSolution: defnumSquares(self, n: int) -> int: while n % 4 == 0: n /= 4 if n % 8 == 7: return4 a = 0 while a**2 <= n: b = int((n - a**2)**0.5) if a**2 + b**2 == n: returnbool(a) + bool(b) a += 1 return3
classSolution: defmoveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ nums.sort(key=bool, reverse=True)
sort 时间复杂度为$O(N\log N)$, 直接遍历可以达到 $O(N)$
1 2 3 4 5 6 7 8 9 10
classSolution: defmoveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ i = 0 for i, n inenumerate(filter(lambda x: x, nums)): nums[i] = n for i inrange(i + 1, len(nums)): nums[i] = 0
classSolution: deftopKFrequent(self, nums: List[int], k: int) -> List[int]: d = {n: 0for n in nums} for n in nums: d[n] += 1 r = [] for _ inrange(k): n = max(d, key=d.get) r.append(n) d[n] = -1 return r
classSolution: defdecodeString(self, s: str) -> str: stack = [['', 1, '']] a = n = '' for c in s: if c.isalpha(): a += c elif c.isdigit(): n += c elif c == '[': stack.append([a, int(n), '']) a = n = '' else: p, t, b = stack.pop() stack[-1][-1] += p + t * (b + a) a = '' return stack.pop()[-1] + a
""" # Definition for a Node. class Node: def __init__(self, val, prev, next, child): self.val = val self.prev = prev self.next = next self.child = child """ from itertools import chain
classSolution: defflatten(self, head: 'Node') -> 'Node': defgen(n): yieldfrom chain([n], gen(n.child), gen(n.next)) if n else () iters = gen(head); p = head andnext(iters) for n in iters: p.next, n.prev, p.child, n.child, p = n, p, None, None, n return head
classSolution: deffindDisappearedNumbers(self, nums: List[int]) -> List[int]: s = set(nums) return [i for i inrange(1, len(nums) + 1) if i notin s]
set 的内部实现为 dict,in 操作时间复杂度为 $O(1)$
应题目进阶要求,以下解为 $O(N)$ 时间效率,无额外空间(除了返回数组和中间变量)
1 2 3 4 5
classSolution: deffindDisappearedNumbers(self, nums: List[int]) -> List[int]: for n in nums: nums[abs(n) - 1] = -abs(nums[abs(n) - 1]) return [i + 1for i, n inenumerate(nums) if n > 0]
classSolution: deffourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int: dic = collections.Counter(a + b for a in A for b in B) returnsum(dic.get(- c - d, 0) for c in C for d in D)
classSolution: deffindDiagonalOrder(self, matrix: List[List[int]]) -> List[int]: m, n, r = len(matrix), len(matrix) andlen(matrix[0]), [] for l inrange(m + n - 1): temp = [matrix[i][l - i] for i inrange(max(0, l+1 - n), min(l+1, m))] r += temp if l % 2else temp[::-1] return r
classSolution: deffindUnsortedSubarray(self, nums: List[int]) -> int: diff = [i for i, (a, b) inenumerate(zip(nums, sorted(nums))) if a != b] returnlen(diff) andmax(diff) - min(diff) + 1
""" # Definition for a Node. class Node: def __init__(self, val=None, children=None): self.val = val self.children = children """ classSolution: defpreorder(self, root: 'Node') -> List[int]: return root andsum([[root.val], *map(self.preorder, root.children)], []) or []
递归解法,利用 and or 控制递归叶节点和普通节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
""" # Definition for a Node. class Node: def __init__(self, val=None, children): self.val = val self.children = children """ classSolution: defpreorder(self, root: 'Node') -> List[int]: s = bool(root) * [root] r = [] while s: root = s.pop() r.append(root.val) s += root.children[::-1] return r
classSolution: deffindRestaurant(self, list1: List[str], list2: List[str]) -> List[str]: d = {x: list1.index(x) + list2.index(x) for x inset(list1) & set(list2)} return [x for x in d if d[x] == min(d.values())]
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: deffindDuplicateSubtrees(self, root): d = collections.defaultdict(list) defdfs(root): ifnot root: return'' s = ' '.join((str(root.val), dfs(root.left), dfs(root.right))) d[s].append(root) return s dfs(root) return [l[0] for l in d.values() iflen(l) > 1]
classSolution(object): defdailyTemperatures(self, T): stack, r = [], [0] * len(T) for i, t inenumerate(T): while stack and T[stack[-1]] < t: r[stack.pop()] = i - stack[-1] stack.append(i) return r
classSolution(object): defisAlienSorted(self, words, order): return words == sorted(words, key=lambda w: [order.index(x) for x in w])
充分利用 python 序列比较的特点,sorted 的参数 key 可传入一个函数,sorted 函数会将每个元素作为输入,输入到 key 函数并获得返回值,整个序列将按此值的大小来排序。此处 key 函数为lambda w: [order.index(x) for x in w],其为words中每个单词 word 返回一个 list,list 中每个元素为单词中字母 x 在 order 中的索引。比如当 order 为 ‘abcde……’ 时,单词 ‘cab’ 将返回 [3, 2, 1]。关于俩个 list 的大小比较,服从 python 序列比较的特性,请参考官方文档教程 5.8 节内容。
classSolution: defisAlienSorted(self, words: List[str], order: str) -> bool: d = {c: i + 1for i, c inenumerate(order)} returnsorted(words, key=lambda x: sum(d[c] * 10**(-2 * i) for i, c inenumerate(x))) == words
def__init__(self, k: int): """ Initialize your data structure here. Set the size of the queue to be k. :param k: :return: """ self.size = 0 self.max_size = k self.data = [0] * k self.front = self.rear = -1
defenQueue(self, value: int) -> bool: """ Insert an element into the circular queue. Return true if the operation is successful. :param value: :return: """ if self.isFull(): returnFalse
self.data[self.rear] = value self.size += 1 returnTrue
defdeQueue(self) -> bool: """ Delete an element from the circular queue. Return true if the operation is successful. :return: """ if self.isEmpty(): returnFalse
# 放入周围的陆地节点 for a, b in around: a += x; b += y; if0 <= a < m and0 <= b < n andint(grid[a][b]): q.put((a, b)) #---------------------------------------------------------------- return r
classSolution: defnumSquares(self, n: int) -> int: around = [] for i inrange(1, n + 1): if i**2 <= n: around.append(i**2) else: break; r = 0 seen = set() # 防止重复运算 # ----------------BFS 开始---------------------- # 初始化根节点 q = Queue() q.put((0, r)) # 进入队列循环 whilenot q.empty(): # 取出一个元素 cur, step = q.get() step += 1 # 放入周围元素 for a in around: a += cur if a == n: return step if a < n and (a, step) notin seen: seen.add((a, step)) q.put((a, step)) # ---------------------------------------------- return0
将当前数字的总和视为节点,加上一个完全平方数后能达到的数字作为一阶邻域,搜索到达 n 的最短路径
☄ 栈:后入先出的数据结构
【知识卡片】栈也是一种数据呈线性排列的数据结构,不过在这种结构中,我们只能访问最新添加的数 据。栈就像是一摞书,拿到新书时我们会把它放在书堆的最上面,取书时也只能从最上面的新书开始取。Last In First Out,简称 LIFO,常常被用于数组中不同位置之间含有 嵌套关系 的题目
# Your MinStack object will be instantiated and called as such: # obj = MinStack() # obj.push(x) # obj.pop() # param_3 = obj.top() # param_4 = obj.getMin()
classSolution: defisValid(self, s: str) -> bool: stack = [] d = {'(': ')', '[': ']', '{': '}'} for p in s: if p in'{[(': stack.append(p) else: ifnot stack or d[stack.pop()] != p: returnFalse returnnot stack
classSolution(object): defdailyTemperatures(self, T): stack = [] r = [0] * len(T) for i, t inenumerate(T): while stack and T[stack[-1]] < t: c = stack.pop() r[c] = i - c stack.append(i) return r
classSolution: defnumIslands(self, grid: List[List[str]]) -> int: try: m = len(grid) n = len(grid[0]) except: return0 # -------------------------DFS 开始------------------------ # 定义dfs递归方程 defdfs(i, j): if0 <= i < m and0 <= j < n andint(grid[i][j]): grid[i][j] = '0' for a, b in ((1, 0), (0, -1), (-1, 0), (0, 1)): dfs(i + a, j + b) # --------------------------------------------------------- r = 0 for i inrange(m): for j inrange(n): r += int(grid[i][j]) dfs(i, j) # 调用dfs沉没一整块陆地 return r
def__init__(self): """ Initialize your data structure here. """ self.stack = []
defpush(self, x: int) -> None: """ Push element x to the back of queue. """ self.stack.append(x)
defpop(self) -> int: """ Removes the element from in front of queue and returns that element. """ temp = [] while self.stack: temp.append(self.stack.pop()) r = temp.pop() while temp: self.stack.append(temp.pop()) return r
defpeek(self) -> int: """ Get the front element. """ temp = [] while self.stack: temp.append(self.stack.pop()) r = temp[-1] while temp: self.stack.append(temp.pop()) return r
defempty(self) -> bool: """ Returns whether the queue is empty. """ returnnot self.stack
# Your MyQueue object will be instantiated and called as such: # obj = MyQueue() # obj.push(x) # param_2 = obj.pop() # param_3 = obj.peek() # param_4 = obj.empty()
def__init__(self): """ Initialize your data structure here. """ self.q = Queue()
defpush(self, x: int) -> None: """ Push element x onto stack. """ self.q.put(x)
defpop(self) -> int: """ Removes the element on top of the stack and returns that element. """ for _ inrange(self.q.qsize() - 1): self.q.put(self.q.get()) return self.q.get()
deftop(self) -> int: """ Get the top element. """ for _ inrange(self.q.qsize() - 1): self.q.put(self.q.get()) r = self.q.get() self.q.put(r) return r defempty(self) -> bool: """ Returns whether the stack is empty. """ return self.q.empty()
# Your MyStack object will be instantiated and called as such: # obj = MyStack() # obj.push(x) # param_2 = obj.pop() # param_3 = obj.top() # param_4 = obj.empty()
classSolution: defdecodeString(self, s: str) -> str: stack = [['', 1, '']] a = n = '' for c in s: if c.isalpha(): a += c elif c.isdigit(): n += c elif c == '[': stack.append([a, int(n), '']) a = n = '' else: p, t, b = stack.pop() stack[-1][-1] += p + t * (b + a) a = '' return stack.pop()[-1] + a
classSolution: deffloodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]: m, n = map(len, (image, image[0])) around = ((1, 0), (0, 1), (-1, 0), (0, -1)) oldColor = image[sr][sc] # 创建栈放入根节点 stack = [(sr, sc)] # 进入循环放入邻居 while stack: r, c = stack.pop() if oldColor != newColor: # 根剪枝 image[r][c] = newColor
for x, y in around: x, y = x + r, y + c if0 <= x < m and0 <= y < n and image[x][y] == oldColor: # 邻剪枝 image[x][y] = newColor stack.append((x, y)) return image
classSolution: defupdateMatrix(self, matrix: List[List[int]]) -> List[List[int]]: m, n = len(matrix), len(matrix[0]) r = [[0] * n for _ inrange(m)] around = ((0, 1), (1, 0), (0, -1), (-1, 0)) for i inrange(m): for j inrange(n): # -------------------------BFS 开始-------------------------- # 放入根节点 q = collections.deque([(i, j, 0)]) seen = {(i, j)} # 循环取节点 while q: a, b, t = q.popleft() ifnot matrix[a][b]: r[i][j] = t break # 放入邻节点 for x, y in around: x, y = x + a, y + b if0 <= x < m and0 <= y < n and (x, y) notin seen: seen.add((x, y)) q.append((x, y, t + 1)) # ---------------------------------------------------------- return r
classSolution: deffindDiagonalOrder(self, matrix: List[List[int]]) -> List[int]: m, n, r = len(matrix), len(matrix) andlen(matrix[0]), [] for l inrange(m + n - 1): temp = [matrix[i][l - i] for i inrange(max(0, l+1 - n), min(l+1, m))] r += temp if l % 2else temp[::-1] return r
classSolution: defgenerate(self, numRows: int) -> List[List[int]]: r = [[1]] for i inrange(1, numRows): r.append([1] + [sum(r[-1][j:j+2]) for j inrange(i)]) return numRows and r or []
classSolution: defaddBinary(self, a: str, b: str) -> str: r, p = '', 0 d = len(b) - len(a) a = '0' * d + a b = '0' * -d + b for i, j inzip(a[::-1], b[::-1]): s = int(i) + int(j) + p r = str(s % 2) + r p = s // 2 return'1' + r if p else r
classSolution: deffindMaxConsecutiveOnes(self, nums: List[int]) -> int: r = c = 0 for n in nums: if n: c += 1 else: r = max(r, c) c = 0 returnmax(r, c)
classSolution: defminSubArrayLen(self, s: int, nums: List[int]) -> int: i, a, r = 0, 0, float('inf') for j inrange(len(nums)): a += nums[j] while a >= s: r = min(r, j - i + 1) a -= nums[i] i += 1 return0if r == float('inf') else r
classSolution: defgetRow(self, rowIndex: int) -> List[int]: r = [1] for i inrange(1, rowIndex + 1): r = [1] + [sum(r[j:j+2]) for j inrange(i)] return r
classSolution: defremoveDuplicates(self, nums: List[int]) -> int: i = 0 for j inrange(1, len(nums)): if nums[j] != nums[i]: i += 1 nums[i] = nums[j] returnlen(nums) and i + 1
classSolution: defmoveZeroes(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ i = 0 for j inrange(len(nums)): if nums[j]: nums[i] = nums[j] i += 1 while i < len(nums): nums[i] = 0 i += 1
classNode: def__init__(self, v, p=None, n=None): self.val = v self.prev = p self.next = n
classMyLinkedList:
def__init__(self): """ Initialize your data structure here. """ self.key = Node(-1) self.key.prev = self.key.next = self.key
defget(self, index: int) -> int: """ Get the value of the index-th node in the linked list. If the index is invalid, return -1. """ i, node = 0, self.key.next while i < index and node != self.key: node = node.next i += 1 return node.val if index >= 0else -1
defaddAtHead(self, val: int) -> None: """ Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. """ self.key.next.prev = self.key.next = Node(val, p=self.key, n=self.key.next)
defaddAtTail(self, val: int) -> None: """ Append a node of value val to the last element of the linked list. """ self.key.prev.next = self.key.prev = Node(val, p=self.key.prev, n=self.key)
defaddAtIndex(self, index: int, val: int) -> None: """ Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. """ index = max(0, index) i, node = 0, self.key.next while i < index and node != self.key: node = node.next i += 1 if node != self.key or i == index: node.prev.next = node.prev = Node(val, p=node.prev, n=node)
defdeleteAtIndex(self, index: int) -> None: """ Delete the index-th node in the linked list, if the index is valid. """ if index < 0: return i, node = 0, self.key.next while i < index and node != self.key: node = node.next i += 1 if node != self.key: node.prev.next = node.next node.next.prev = node.prev del node
# Your MyLinkedList object will be instantiated and called as such: # obj = MyLinkedList() # param_1 = obj.get(index) # obj.addAtHead(val) # obj.addAtTail(val) # obj.addAtIndex(index,val) # obj.deleteAtIndex(index)
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None
classSolution(object): defhasCycle(self, head): slow = fast = head while fast and fast.next: fast = fast.next.next slow = slow.next if slow == fast: returnTrue returnFalse
classSolution(object): defdetectCycle(self, head): slow = fast = head while fast and fast.next: fast = fast.next.next slow = slow.next if slow == fast: break else: returnNone while head isnot slow: head = head.next slow = slow.next return head
设环的起始节点为 E,快慢指针从 head 出发,快指针速度为 2,设相交节点为 X,head 到 E 的距离为 H,E 到 X 的距离为 D,环的长度为 L,那么有:快指针走过的距离等于慢指针走过的距离加快指针多走的距离(多走了 n 圈的 L) 2(H + D) = H + D + nL,因此可以推出 H = nL - D,这意味着如果我们让俩个慢指针一个从 head 出发,一个从 X 出发的话,他们一定会在节点 E 相遇
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None
classSolution(object): defgetIntersectionNode(self, headA, headB): """ :type head1, head1: ListNode :rtype: ListNode """ a, b = (headA, headB) if headA and headB else (None, None) while a != b: a, b = not a and headB or a.next, not b and headA or b.next return a
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defremoveNthFromEnd(self, head: ListNode, n: int) -> ListNode: link = [] while head: link.append(head) head = head.next if n != len(link): link[-n - 1].next = link[-n].next del link[-n] return link and link[0]
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defremoveElements(self, head: ListNode, val: int) -> ListNode: while head and head.val == val: head = head.next pre, cur = head, head and head.next while cur: if cur.val == val: pre.next = cur = cur.next else: pre, cur = cur, cur.next return head
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defisPalindrome(self, head: ListNode) -> bool: s, f, p = head, head, None while f and f.next: s.next, p, s, f = p, s, s.next, f.next.next if f: s = s and s.next while s and p and s.val == p.val: p, s = p.next, s.next return s == p == None
f 记录快指针,每次走倆步,s 记录慢指针,每次走一步,p 记录 s 的前一个节点
首先使用快慢指针找到中点,第一个 while 停止时如果链表长度为奇数,s 为中点;否则 f 为 None,s 为右半部分的第一个节点
""" # Definition for a Node. class Node: def __init__(self, val, prev, next, child): self.val = val self.prev = prev self.next = next self.child = child """ classSolution: defflatten(self, head: 'Node') -> 'Node': stack = [head] if head else [] p = None while stack: node = stack.pop() if node.next: stack.append(node.next) if node.child: stack.append(node.child) if p: p.next = node node.prev = p p.child = node.child = None p = node return head
classNode: def__init__(self, val, nex): self.val = val self.nex = nex
classMyHashSet:
def__init__(self): """ Initialize your data structure here. """ self.size = 1000 self.h = [Node(None, None) for _ inrange(self.size)]
defadd(self, key: int) -> None: p = self.h[key % self.size] node = p.nex while node: if node.val == key: break p = node node = node.nex else: p.nex = Node(key, None)
defremove(self, key: int) -> None: p = self.h[key % self.size] node = p.nex while node: if node.val == key: p.nex = node.nex break p = node node = node.nex
defcontains(self, key: int) -> bool: """ Returns true if this set contains the specified element """ node = self.h[key % self.size] while node: if node.val == key: returnTrue node = node.nex returnFalse
# Your MyHashSet object will be instantiated and called as such: # obj = MyHashSet() # obj.add(key) # obj.remove(key) # param_3 = obj.contains(key)
def__init__(self): """ Initialize your data structure here. """ self.size = 1000 self.h = [Node() for _ inrange(self.size)]
defput(self, key: int, value: int) -> None: """ value will always be non-negative. """ p = self.h[key % self.size] c = p.nex while c: if c.key == key: c.val = value break p = c c = c.nex else: p.nex = Node(key, value)
defget(self, key: int) -> int: """ Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key """ c = self.h[key % self.size] while c: if c.key == key: return c.val c = c.nex return -1
defremove(self, key: int) -> None: """ Removes the mapping of the specified value key if this map contains a mapping for the key """ p = self.h[key % self.size] c = p.nex while c: if c.key == key: p.nex = c.nex break p = c c = c.nex
# Your MyHashMap object will be instantiated and called as such: # obj = MyHashMap() # obj.put(key,value) # param_2 = obj.get(key) # obj.remove(key)
classSolution: deftwoSum(self, nums: List[int], target: int) -> List[int]: d = {} for i, n inenumerate(nums): if n in d: return [d[n], i] d[target-n] = i
classSolution: deffindRestaurant(self, list1: List[str], list2: List[str]) -> List[str]: d = {x: list1.index(x) + list2.index(x) for x inset(list1) & set(list2)} return [x for x in d if d[x] == min(d.values())]
classSolution: defcontainsNearbyDuplicate(self, nums: List[int], k: int) -> bool: r = float('inf') d = {} for i, n inenumerate(nums): r = min(r, i - d.get(n, float('-inf'))) d[n] = i return r <= k
classSolution: defgroupAnagrams(self, strs: List[str]) -> List[List[str]]: d = collections.defaultdict(list) for s in strs: d[''.join(sorted(s))].append(s) return [*d.values()]
classSolution: defisValidSudoku(self, board: List[List[str]]) -> bool: row, col, pal = eval(','.join(['[[0] * 9 for _ in range(9)]'] * 3)) for i, r inenumerate(board): for j, n inenumerate(r): if n == '.': continue n = int(n) - 1 if row[i][n] or col[j][n] or pal[i // 3 * 3 + j // 3][n]: returnFalse row[i][n] = col[j][n] = pal[i // 3 * 3 + j // 3][n] = 1 returnTrue
classSolution: deflengthOfLongestSubstring(self, s: str) -> int: i, r, d = -1, 0, {} for j, c inenumerate(s): i = max(i, d.get(c, -1)) r = max(r, j - i) d[c] = j return r
classSolution: deftopKFrequent(self, nums: List[int], k: int) -> List[int]: d = {n: 0for n in nums} for n in nums: d[n] += 1 r = [] for _ inrange(k): n = max(d, key=d.get) r.append(n) d[n] = -1 return r
def__init__(self): """ Initialize your data structure here. """ self.d = {} self.l = []
definsert(self, val: int) -> bool: """ Inserts a value to the set. Returns true if the set did not already contain the specified element. """ if val in self.d: returnFalse else: self.d[val] = len(self.l) self.l.append(val) returnTrue
defremove(self, val: int) -> bool: """ Removes a value from the set. Returns true if the set contained the specified element. """ if val in self.d: self.d[self.l[-1]] = self.d[val] self.l[self.d.pop(val)] = self.l[-1] self.l.pop() returnTrue else: returnFalse
defgetRandom(self) -> int: """ Get a random element from the set. """ return self.l[random.randint(0, len(self.l) - 1)]
# Your RandomizedSet object will be instantiated and called as such: # obj = RandomizedSet() # param_1 = obj.insert(val) # param_2 = obj.remove(val) # param_3 = obj.getRandom()
classSolution: def二分查找二岔模板(self, nums: List[int], target: int): l, h = 0, len(nums) while l < h: m = (l + h) // 2 if 必须向左搜索的条件: h = m else: l = m + 1 return l - 1
【非内置公式B】
1 2 3 4 5 6 7 8 9 10
classSolution: def二分查找二岔模板(self, nums: List[int], target: int): l, h = 0, len(nums) - 1 while l < h: m = (l + h) // 2 if 满足目标或向左搜索的条件: h = m else: l = m + 1 return l
classSolution: defsearch(self, nums: List[int], target: int) -> int: l, h = 0, len(nums) - 1 while l <= h: m = (l + h) // 2 if nums[m] == target: return m elif nums[m] > target: h = m - 1 else: l = m + 1 return -1
classSolution: defmySqrt(self, x: int) -> int: l, h = 0, x while l < h: m = (l + h) // 2 if m**2 <= x < (m+1)**2: return m elif m**2 < x: l = m + 1 else: h = m - 1 return l
# The guess API is already defined for you. # @param num, your guess # @return -1 if my number is lower, 1 if my number is higher, otherwise return 0 # def guess(num):
classSolution(object): defguessNumber(self, n): """ :type n: int :rtype: int """ l, h = 1, n while l <= n: m = (l + h) // 2 r = guess(m) ifnot r: return m elif r == 1: l = m + 1 else: h = m - 1
# The isBadVersion API is already defined for you. # @param version, an integer # @return a bool # def isBadVersion(version):
classSolution: deffirstBadVersion(self, n): """ :type n: int :rtype: int """ l, h = 1, n while l <= h: m = (l + h) // 2 if isBadVersion(m) > m * isBadVersion(m - 1): return m elif isBadVersion(m): h = m - 1 else: l = m + 1
本题二分搜索中判断返回的条件为 当前版本为True且(当前索引为0 或 左边的版本为False)
m * 的作用是避免 m - 1 为负数,如果 m 为 0,则代表左边没有版本,只需判断当前版本是否为 True
classSolution: deffindPeakElement(self, nums: List[int]) -> int: l, h = 0, len(nums) - 1 while l <= h: m = (l + h) // 2 if (not m or nums[m-1] < nums[m]) and (m == len(nums) - 1or nums[m] > nums[m+1]): return m elifnot m or nums[m] > nums[m-1]: l = m + 1 else: h = m - 1
classSolution: deffindMin(self, nums: List[int]) -> int: l, h = 0, len(nums) - 1 while l < h: m = (l + h) // 2 if nums[m] < nums[-1]: h = m else: l = m + 1 return nums[l]
classSolution: defsearchRange(self, nums: List[int], target: int) -> List[int]: r = [-1, -1] l, h = 0, len(nums) - 1 while l < h: m = (l + h) // 2 if target <= nums[m]: h = m else: l = m + 1 if nums and nums[l] == target: r[0] = l l, h = 0, len(nums) - 1 while l < h: m = (l + h) // 2 if target < nums[m] or (target == nums[m] and (m == len(nums) - 1or nums[m] < nums[m+1])): h = m else: l = m + 1 if nums and nums[l] == target: r[1] = l return r
classSolution: deffindPeakElement(self, nums: List[int]) -> int: l, h = 0, len(nums) - 1 while l <= h: m = (l + h) // 2 if (not m or nums[m-1] < nums[m]) and (m == len(nums) - 1or nums[m] > nums[m+1]): return m elifnot m or nums[m] > nums[m-1]: l = m + 1 else: h = m - 1
classSolution: defisPerfectSquare(self, num: int) -> bool: l, h = 0, num while l < h: m = (l + h) // 2 if m * m >= num: h = m else: l = m + 1 return l * l == num
classSolution: defnextGreatestLetter(self, letters: List[str], target: str) -> str: l, h = 0, len(letters) - 1 while l < h: m = (l + h) // 2 if letters[m] > target: h = m else: l = m + 1 return letters[l] if letters[l] > target else letters[0]
classSolution: deffindMin(self, nums: List[int]) -> int: l, h = 0, len(nums) - 1 while l < h: m = (l + h) // 2 if nums[m] < nums[-1]: h = m else: l = m + 1 return nums[l]
classSolution: deffindMin(self, nums: List[int]) -> int: l, h = 0, len(nums) - 1 while l < h: m = (l + h) // 2 if nums[m] < nums[h]: h = m elif nums[m] == nums[h]: h -= 1 else: l = m + 1 return nums[l]
每次都需要判断 m 是否在未被旋转的部分上(右部),如果在,则向左搜索,否则向右搜索
当 nums[m] < nums[h] 时可以确定在右部,由于存在重复数字,当 m 指向的数字和 h 指向的相同时,可以直接收缩搜索范围(h -= 1),反正他们所代表的数字还有至少一个在搜索范围内
classSolution: deffindDuplicate(self, nums: List[int]) -> int: l, h = 0, len(nums) - 1 while l < h: m = (l + h) >> 1 ifsum(n <= m for n in nums) > m: h = m else: l = m + 1 return l
本题可用二分查找,整个算法时间复杂度为 O(NlogN),由题意可知搜索范围在 1 到 n 之间,那么如何缩小范围?只需判断数组中不超过中间数 m 的元素数量是否大于 m 即可,若大于,则表示范围 1 到 m 内肯定包含重复的数字
搜索范围为 [1, n],向左(包括target)搜索的条件为:不大于 n 的数字在 nums 存在超过 m 个,即搜索范围可以被缩小为 [1, m]
1 2 3 4
classSolution: deffindDuplicate(self, nums: List[int]) -> int: self.__class__.__getitem__ = lambda sef, m: sum(n <= m for n in nums) > m return bisect.bisect_left(self, True, 1, len(nums) - 1)
classSolution: deffindMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: iflen(nums1) < len(nums2): a, b = nums1, nums2 else: a, b = nums2, nums1 m = (len(nums1) + len(nums2) - 1) >> 1 l, h = 0, len(a) while l < h: i = (l + h) >> 1 if m-i-1 < 0or a[i] >= b[m-i-1]: h = i else: l = i + 1 r = sorted(a[l: l + 2] + b[m - l: m - l + 2]) return (r[0] + r[1 - (len(a) + len(b)) % 2]) / 2
classSolution: defsmallestDistancePair(self, nums: List[int], k: int) -> int: nums.sort() l, h = 0, max(nums) - min(nums) while l < h: m = (l + h) >> 1 # 滑动窗口求小于 m 的对数 c = j = 0 for i, n inenumerate(nums[:-1]): while j < len(nums) and nums[j] - nums[i] <= m: j += 1 c += j - i - 1 if c >= k: h = m else: l = m + 1 return l
classSolution: defsplitArray(self, nums: List[int], m: int) -> int: l, h = 0, sum(nums) while l < h: mid = (l + h) >> 1 # 贪心试错 c = 1; r = s = 0 for i, n inenumerate(nums): if s + n > mid: c += 1 r = max(r, s) s = n else: s += n r = max(r, s) if c <= m and r <= mid: h = mid else: l = mid + 1 return l
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: defpreorderTraversal(self, root: TreeNode) -> List[int]: r, stack = [], root and [root] or [] while stack: root = stack.pop() r.append(root.val) stack += root.right and [root.right] or [] stack += root.left and [root.left] or [] return r
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: defhasPathSum(self, root: TreeNode, sum: int) -> bool: if root: if root.left is root.right: returnsum == root.val else: l = root.left and self.hasPathSum(root.left, sum - root.val) r = root.right and self.hasPathSum(root.right, sum - root.val) return l or r else: returnFalse
考虑初始状态:当树不存在时直接返回 False
考虑支路1:当前节点为叶节点时直接判断总和是否达到要求
考虑支路2:当前节点为非叶节点时将总和缩小并继续递归,判断左右节点是否存在满足条件的
当递归函数到达叶节点时,sum 已经被削减了多次,此时 sum - node.val 即为 原始的sum - 整条路径的总和
""" # Definition for a Node. class Node: def __init__(self, val, left, right, next): self.val = val self.left = left self.right = right self.next = next """ classSolution: defconnect(self, root: 'Node') -> 'Node': if root and root.left: root.left.next = root.right if root.next: root.right.next = root.next.left self.connect(root.left) self.connect(root.right) return root
""" # Definition for a Node. class Node: def __init__(self, val, left, right, next): self.val = val self.left = left self.right = right self.next = next """ classSolution: defconnect(self, root: 'Node') -> 'Node': if root and (root.left or root.right): if root.left and root.right: root.left.next = root.right node = root.right or root.left head = root.next while head andnot (head.left or head.right): head = head.next node.next = head and (head.left or head.right) self.connect(root.right) self.connect(root.left) return root
对于任意一次递归,只考虑如何设置子节点的 next 属性,分为三种情况:
没有子节点:直接返回
有一个子节点:将这个子节点的 next 属性设置为同层的下一个节点,即为 root.next 的最左边的一个节点,如果 root.next 没有子节点,则考虑 root.next.next,依次类推
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: deflowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': l = root.left and self.lowestCommonAncestor(root.left, p, q) r = root.right and self.lowestCommonAncestor(root.right, p, q) return root if root in (p, q) or l and r else l or r
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classCodec:
defserialize(self, root): """Encodes a tree to a single string. :type root: TreeNode :rtype: str """ l = [] q = collections.deque([root]) while q: root = q.popleft() if root: l.append(root.val) q.extend([root.left, root.right]) else: l.append(None) returnstr(l)
defdeserialize(self, data): """Decodes your encoded data to tree. :type data: str :rtype: TreeNode """ l = eval(data) head = TreeNode(l[0]) if l[0] isnotNoneelseNone q = collections.deque([head]) i = 1 while q: root = q.popleft() if root isnotNone: root.left = TreeNode(l[i]) if l[i] isnotNoneelseNone root.right = TreeNode(l[i + 1]) if l[i + 1] isnotNoneelseNone i += 2 q.extend([root.left, root.right]) return head
# Your Codec object will be instantiated and called as such: # codec = Codec() # codec.deserialize(codec.serialize(root))
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: defisValidBST(self, root: TreeNode, first=True) -> bool: ifnot root: return first or [] f = self.isValidBST l = f(root.left, 0) + [root.val] + f(root.right, 0) returnall([a > b for a, b inzip(l[1:], l)]) if first else l
defnext(self) -> int: """ @return the next smallest number """ r = self.s.pop() root = r.right while root: self.s.append(root) root = root.left return r.val
defhasNext(self) -> bool: """ @return whether we have a next smallest number """ returnbool(self.s)
# Your BSTIterator object will be instantiated and called as such: # obj = BSTIterator(root) # param_1 = obj.next() # param_2 = obj.hasNext()
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None
classSolution: deflowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': l = root.left and self.lowestCommonAncestor(root.left, p, q) r = root.right and self.lowestCommonAncestor(root.right, p, q) if root in (p, q) or l and r: return root else: return l or r
classSolution: defcontainsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool: l = [] for j, n inenumerate(nums): if j > k: # 滑动窗口 del l[bisect.bisect_left(l, nums[j - k - 1], 0, len(l))] i = bisect.bisect_left(l, n, 0, len(l)) l.insert(i, n) if i andabs(l[i] - l[i - 1]) <= t or i < len(l) - 1andabs(l[i] - l[i + 1]) <= t: returnTrue returnFalse
k 实际上限制了滑动窗口的大小,对于每个数字,我们只需要检查其前面的 k-1 个数字中是否存在与当前数字距离不超过 t 的数字即可
检查的方法是在升序的列表中检查当前数字所在索引的左右两侧是否波动不超过 t
因为使用了窗口,所以维护排序只需在之前已经排好序的数组 l 的基础上保持升序得插入新数字即可,这里使用二分查找搜索插入位置
""" # Definition for a Node. class Node: def __init__(self, val=None, children): self.val = val self.children = children """ classSolution: defpreorder(self, root: 'Node') -> List[int]: s = bool(root) * [root] r = [] while s: root = s.pop() r.append(root.val) s += root.children[::-1] return r
""" # Definition for a Node. class Node: def __init__(self, val=None, children=None): self.val = val self.children = children """ classSolution: defpostorder(self, root: 'Node') -> List[int]: s = bool(root) * [root] r = [] while s: root = s.pop() r.append(root.val) s += root.children return r[::-1]
classSolution: defreverseString(self, s: List[str]) -> None: """ Do not return anything, modify s in-place instead. """ for i inrange(len(s) - 1, 0, -1): s.insert(i, s.pop(0))
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None
classSolution: defswapPairs(self, head: ListNode) -> ListNode: if head and head.next: seco = head.next head.next = self.swapPairs(seco.next) seco.next = head return seco return head
# Definition for a binary tree node. classTreeNode: def__init__(self, x, l=None, r=None): self.val = x self.left = l self.right = r
classSolution: defgenerateTrees(self, n: int) -> List[TreeNode]: defgen(num): ifnot num: yieldNone for i, n inenumerate(num): for l in gen(num[:i]): for r in gen(num[i + 1:]): yield TreeNode(n, l, r) returnbool(n) * [*gen([*range(1, 1 + n)])]