赞
踩
- def preorderTraversal(self, root: TreeNode) -> List[int]:
- if root == None:
- return []
- # 分别记录遍历结果,存储栈
- result, istack = [], []
- while root != None or len(istack) != 0:
- # 嵌套循环
- while root != None:
- # 前序遍历,压入栈前先输出
- result.append(root.val)
- istack.append(root)
- root=root.left
- # 栈弹出
- root = istack[-1]
- istack = istack[:-1]
- root = root.right
- return result
2.中序遍历:
- def inorderTraversal(self, root: TreeNode) -> List[int]:
- if root == None:
- return []
- # 分别记录遍历结果,存储栈
- result, istack = [], []
- while root != None or len(istack) != 0:
- while root != None:
- istack.append(root)
- root = root.left
- # 中序遍历,等左子树压入栈完毕,再从栈输出
- cur = istack[-1]
- result.append(cur.val)
- istack = istack[:-1]
- root = cur.right
- return result
3.后序遍历:
- def postorderTraversal(self, root: TreeNode) -> List[int]:
- if root == None:
- return []
- # 分别记录遍历结果,存储栈,后序遍历必要的前一个输出节点记录
- result, istack, lastnode = [], [], None
- while root != None or len(istack) != 0:
- while root != None:
- istack.append(root)
- root = root.left
- # 左子树压入栈后,判断当前节点是否可输出
- cur = istack[-1]
- # 如果当前节点无右子树,或者右子树已经输出,则该点可输出
- if cur.right == None or cur.right == lastnode:
- istack = istack[:-1]
- result.append(cur.val)
- lastnode = cur
- # 否则继续将该点右子树入栈,再继续循环
- else:
- root = cur.right
- return result
深度搜索DFS,层次搜索BFS:
- def levelOrder(self, root: TreeNode) -> List[List[int]]:
- if root == None:
- return []
- # 层序遍历,需要借助队列记录
- result, iqueue = [], []
- # 队列需要先入队
- iqueue.append(root)
- while len(iqueue) != 0:
- # 遍历当前层之前,先记录该层的个数,以便队列边记录边遍历
- l, temp = len(iqueue), []
- for i in range(0, l):
- # 遍历时,依次取出和输出队中的点,并将子树入队
- cur = iqueue[0]
- iqueue = iqueue[1:]
- temp.append(cur.val)
- if cur.left != None:
- iqueue.append(cur.left)
- if cur.right != None:
- iqueue.append(cur.right)
- result.append(temp)
- return result
分治法:递归返回条件+分段处理+合并结果(快速排序、归并排序、二叉树)
- def maxDepth(self, root: TreeNode) -> int:
- if root == None:
- return 0
- left = self.maxDepth(root.left)
- right = self.maxDepth(root.right)
- return left + 1 if left > right else right + 1
2.判断是否为平衡二叉树:
- def isBalanced(self, root: TreeNode) -> bool:
- if self.judge(root) == -1:
- return False
- else:
- return True
- def judge(self, root: TreeNode) -> int:
- if root == None:
- return 0
- left = self.judge(root.left)
- right = self.judge(root.right)
- # 借助层数来记录是否平衡,如果为-1,则直接返回不平衡
- if left == -1 or right == -1 or left - right > 1 or right - left > 1:
- return -1
- else:
- return left + 1 if left > right else right + 1
3.找出二叉树中最大路径和【hard】
- def maxPathSum(self, root: TreeNode) -> int:
- # 最大和:左/右子树最大和,左右子树加根节点的最大和
- summax = self.find(root)
- return summax[1]
-
- def find(self, root: TreeNode) -> List[int]:
- if root == None:
- return [0, float('-inf')]
- # 分治
- left = self.find(root.left)
- right = self.find(root.right)
- result = []
- # 合并规整,先求单边值,再求最大和
- if left[0] > right[0]:
- result.append(max(left[0] + root.val, 0))
- else:
- result.append(max(right[0] + root.val, 0))
- result.append(max(max(left[1], right[1]), (left[0] + right[0] + root.val)))
- return result
4.找出二叉树的公共祖先
- def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
- if root == None:
- return root
- if root == p or root == q:
- return root
- # 分治
- left = self.lowestCommonAncestor(root.left, p, q)
- right = self.lowestCommonAncestor(root.right, p, q)
- # 归并整合,返回为空则未找到,返回不为空则找到
- if left != None and right != None:
- return root
- if left != None:
- return left
- if right != None:
- return right
- return None
BFS层次遍历:
- def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
- if root == None:
- return []
- # 层次遍历需要借助队列顺序,锯齿形需要逆转标记
- result, iqueue, iturn = [], [], True
- iqueue.append(root)
- while len(iqueue) > 0:
- temp, l = [], len(iqueue)
- for i in range(0, l):
- cur = iqueue[0]
- iqueue = iqueue[1:]
- if iturn:
- temp.append(cur.val)
- else:
- temp.insert(0, cur.val)
- if cur.left != None:
- iqueue.append(cur.left)
- if cur.right != None:
- iqueue.append(cur.right)
- if iturn:
- iturn = False
- else:
- iturn = True
- result.append(temp)
- return result
2.判定是否为有效二叉搜索树【medium】
- def isValidBST(self, root: TreeNode) -> bool:
- res = self.helper(root)
- if res[0] == 0:
- return False
- else:
- return True
- def helper(self, root: TreeNode) -> List[int]:
- # 结果记录,分别为0是否有效,1树的最大值,2树的最小值
- if root == None:
- return [1, float('-inf'), float('-inf')]
- # 分治
- left = self.helper(root.left)
- right = self.helper(root.right)
- # 整合:先判定无效情况
- if left[0] == 0 or right[0] == 0:
- return [0, float('-inf'), float('-inf')]
- if left[1] != float('-inf') and left[1] >= root.val:
- return [0, float('-inf'), float('-inf')]
- if right[2] != float('-inf') and right[2] <= root.val:
- return [0, float('-inf'), float('-inf')]
- # 节点为有效时,节点最大值为右子树的最大值,最小值为左子树的最小值,否则最大最小值为本身
- result = [1, root.val, root.val]
- if right[1] != float('-inf'):
- result[1] = right[1]
- if left[2] != float('-inf'):
- result[2] = left[2]
- return result
3.二叉搜索树中插值:
- def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
- if root == None:
- root = TreeNode()
- root.val = val
- return root
- if root.val == val:
- return root
- elif val < root.val:
- root.left = self.insertIntoBST(root.left, val)
- else:
- root.right = self.insertIntoBST(root.right, val)
- return root
- def deleteDuplicates(self, head: ListNode) -> ListNode:
- pre = ListNode()
- pre.next = head
- head, last = pre, float('inf')
- # 删除重复的额外点,只需要一个指针滑动,判断当前点和下一点(如有);
- # 而删除全部重复点,则需要空指针领头,进行领头后续两个节点的判断(无两个节点则无需判断)。
- while head.next != None and head.next.next != None:
- if head.next.val == head.next.next.val:
- last = head.next.val
- while head.next != None and head.next.val == last:
- head.next = head.next.next
- else:
- head = head.next
- return pre.next
2.反转链表
- def reverseList(self, head: ListNode) -> ListNode:
- pre = ListNode()
- pre.next = head
- while head.next != None:
- # 记录下一个节点
- last = head.next
- # 将当前节点next指向下一个节点的next
- head.next = last.next
- # 下一个节点next指向空指针next
- last.next = pre.next
- # 将空指针移动至最左
- pre.next = last
- return pre.next
3.将指定段落的链表反转【medium】
- def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
- if head == None or m == n:
- return head
- # 先进行小节点检索
- point = ListNode()
- point.next = head
- head = point
- count = 1
- while count < m:
- head = head.next
- count += 1
- pre, mid = head, head.next
- head = head.next
- last = head
- # 用head作为原始遍历顺序指针,last记录移动的前一个结点
- while count <= n and head != None:
- # 将head指针的下一个记录,将当前节点的指针指向上一个节点
- temp = head.next
- head.next = last
- # 移动上一个节点,并将head指针放在原来的下一个
- last = head
- head = temp
- count += 1
- pre.next = last
- mid.next = head
- return point.next
4.拼接两个有序链表
- def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
- # 将合并后的表新起一个空指针作为起点(表头)
- result = ListNode()
- point = result
- while l1 != None and l2 != None:
- if l1.val <= l2.val:
- point.next = l1
- l1 = l1.next
- else:
- point.next = l2
- l2 = l2.next
- point = point.next
- if l1 != None:
- point.next = l1
- if l2 != None:
- point.next = l2
- return result.next
链表分隔与排序:
- def partition(self, head: ListNode, x: int) -> ListNode:
- # 需要用空指针作为原始起点的记录,用额外的表记录比x大的节点,再将结果并至指针末尾
- result, pre = ListNode(), ListNode()
- pre.next = head
- bigger, head = result, pre
- while head.next != None:
- if head.next.val < x:
- head = head.next
- else:
- # 将大值节点记录,移动指针,同时将大值节点链入额外记录链表中
- node = head.next
- head.next = node.next
- bigger.next = node
- bigger = bigger.next
- bigger.next = None
- head.next = result.next
- return pre.next
2.归并排序【medium】
- def sortList(self, head: ListNode) -> ListNode:
- return self.mergeSort(head)
-
- def findMiddle(self, head: ListNode) -> ListNode:
- # 用快慢指针来寻找中间节点
- slow = head
- fast = head.next
- while fast != None and fast.next != None:
- fast = fast.next.next
- slow = slow.next
- return slow
- # 拼接两个有序链表
- def mergeTwo(self, l1: ListNode, l2: ListNode) -> ListNode:
- pre = ListNode()
- point = pre
- while l1 != None and l2 != None:
- if l1.val < l2.val:
- point.next = l1
- l1 = l1.next
- else:
- point.next = l2
- l2 = l2.next
- point = point.next
- if l1 != None:
- point.next = l1
- if l2 != None:
- point.next = l2
- return pre.next
-
- def mergeSort(self, head: ListNode) -> ListNode:
- # 分治法要点1:递归返回确定,这里对至少2个节点排序,故而要有两个判断条件
- if head == None or head.next == None:
- return head
- mid = self.findMiddle(head)
- last = mid.next
- mid.next = None
- # 分治法要点2:分两部分递归,利用快慢指针找到中间节点
- left = self.mergeSort(head)
- right = self.mergeSort(last)
- # 分治法要点3:归并整合两部分,用合并有序链表的方法
- return self.mergeTwo(left, right)
3.将链表按照1, n, 2, n-1, 3, n-2, ..., 的顺序排列
- def reorderList(self, head: ListNode) -> None:
- # 思路:从中间破开链表,反转后链,再合并
- if head == None or head.next == None:
- return head
- mid = self.findMiddle(head)
- last = self.reverseList(mid.next)
- mid.next = None
- head = self.mergeTwo(head, last)
-
- def findMiddle(self, head: ListNode) -> ListNode:
- slow, fast = head, head.next
- while fast != None and fast.next != None:
- fast = fast.next.next
- slow = slow.next
- return slow
-
- def reverseList(self, head: ListNode) -> ListNode:
- pre = ListNode()
- pre.next = head
- while head.next != None:
- last = head.next
- head.next = last.next
- last.next = pre.next
- pre.next = last
- return pre.next
-
- def mergeTwo(self, left: ListNode, right: ListNode) -> ListNode:
- pre, isleft = ListNode(), True
- point = pre
- while left != None and right != None:
- if isleft:
- point.next = left
- left = left.next
- isleft = False
- else:
- point.next = right
- right = right.next
- isleft = True
- point = point.next
- if left != None:
- point.next = left
- if right != None:
- point.next = right
- return pre.next
环状链表:
- def hasCycle(self, head: ListNode) -> bool:
- if head == None:
- return False
- # 快指针用head表示,相交时当前点即为交汇点;
- # 如用head.next表示,则相交点为下一个点
- slow, fast = head, head.next
- # 仅需判断快指针
- while fast != None and fast.next != None:
- if slow == fast:
- return True
- slow = slow.next
- fast = fast.next.next
- return False
2.找出带环链表的入环点
- def detectCycle(self, head: ListNode) -> ListNode:
- if head == None:
- return head
- # 相交点时,快慢指针分别走过a+b,a+n(b+c),c表示环剩下的长度;
- # 得2(a+b)=a+n(b+c),即a=c+(n-1)(b+c),表示a的长度为n-1圈的环+c;
- # 而慢指针继续走c即可回到入环点,再经过n-1圈仍然在入环点;
- slow, fast = head, head.next
- while fast != None and fast.next != None:
- if fast == slow:
- fast = head
- # 因为一开始fast=head.next,此时slow.next才是真当前点
- slow = slow.next
- while fast != slow:
- fast = fast.next
- slow = slow.next
- return slow
- fast = fast.next.next
- slow = slow.next
- return None
回文链表:
- def isPalindrome(self, head: ListNode) -> bool:
- if head == None or head.next == None:
- return True
- # 思路:与前面置换插入排序类似,采用中点截断、反转后链、再比较的做法。
- slow, fast = head, head.next
- while fast != None and fast.next != None:
- slow = slow.next
- fast = fast.next.next
- last = self.reverseList(slow.next)
- slow.next = None
- while last != None and head != None:
- if last.val != head.val:
- return False
- last, head = last.next, head.next
- return True
-
- def reverseList(self, head: ListNode) -> ListNode:
- if head == None:
- return head
- pre = ListNode()
- # 切记,在反转链表时,空指针不需要head辅助
- pre.next = head
- while head.next != None:
- node = head.next
- head.next = node.next
- node.next = pre.next
- pre.next = node
- return pre.next
2.深拷贝链表【medium】
- def copyRandomList(self, head: 'Node') -> 'Node':
- if head == None:
- return head
- point = head
- while point != None:
- node = Node(point.val, point.next)
- point.next = node
- point = node.next
- point = head
- # 很精妙,采用判断前一个节点为非空,来操作空节点
- while point != None:
- if point.random != None:
- point.next.random = point.random.next
- point = point.next.next
- # 原做法
- # node = point.random
- # if node != None:
- # point.random = node.next
- # if point.next != None:
- # point = point.next.next
- # else:
- # point = point.next
- point = head.next
- while head != None and head.next != None:
- # 很精妙,采用指针穿线的方法
- node = head.next
- head.next = head.next.next
- head = node
- return point
- class MinStack:
- def __init__(self,):
- self.istack = []
- self.minstack = []
- # 采用辅助栈做法,记录每个位置的最小值
-
- def push(self, x: int) -> None:
- self.istack.append(x)
- if len(self.minstack) != 0 and self.minstack[-1] < x:
- temp = self.minstack[-1]
- self.minstack.append(temp)
- else:
- self.minstack.append(x)
-
- def pop(self) -> None:
- if len(self.istack) == 0:
- return
- self.istack = self.istack[:-1]
- self.minstack = self.minstack[:-1]
-
- def top(self) -> int:
- if len(self.istack) == 0:
- return 0
- return self.istack[-1]
-
- def getMin(self) -> int:
- if len(self.istack) == 0:
- return float('inf')
- return self.minstack[-1]
2.利用栈进行逆波兰表达式求解
- class Solution:
- def evalRPN(self, tokens: List[str]) -> int:
- if len(tokens) == 0:
- return 0
- istack = []
- for i in range(0, len(tokens)):
- # 关键:会有二位数,因此先判断是否符号,并且是符号还要判断是否有已有两个值在栈中
- if tokens[i] not in ["+", "-", "*", "/"]:
- istack.append(int(tokens[i]))
- elif len(istack) < 2:
- break
- else:
- a, b = istack[-2], istack[-1]
- istack = istack[:-2]
- if tokens[i] == "+":
- istack.append(a + b)
- elif tokens[i] == "-":
- istack.append(a - b)
- elif tokens[i] == "*":
- istack.append(a * b)
- elif tokens[i] == "/":
- istack.append(int(a / b))
- else:
- pass
- if len(istack) == 1:
- return istack[0]
- else:
- return 0
3.字符串解码
- def decodeString(self, s: str) -> str:
- istack = []
- for i in range(0, len(s)):
- if s[i] == ']':
- # 找字符串
- temp = []
- while len(istack) > 0 and istack[-1] != '[':
- temp.insert(0, istack[-1])
- istack = istack[:-1]
- istack = istack[:-1]
- # 找数字
- number = 1
- ilen = len(istack)
- while ilen >= number and istack[ilen - number] in ['0','1','2','3','4','5','6','7','8','9']:
- number += 1
- # 数字范围:[len - i + 1, len - 1]
- res = int(''.join(istack[ilen - number + 1:]))
- istack = istack[:ilen - number + 1]
- # 复制
- for i in range(0, res):
- istack.extend(temp)
- else:
- istack.append(s[i])
- return ''.join(istack)
4.克隆图
- def cloneGraph(self, node: 'Node') -> 'Node':
- # 关键点:用visited记录新建的节点,以连接
- visited = {}
- return self.cloneg(node, visited)
-
- def cloneg(self, node: 'Node', visited: dict) -> 'Node':
- if node == None:
- return node
- # visited中能找到新建节点,则直接返回节点
- if visited.get(node) != None:
- return visited[node]
- newnode = Node(node.val, [])
- visited[node] = newnode
- for n in range(0, len(node.neighbors)):
- newnode.neighbors.append(self.cloneg(node.neighbors[n], visited))
- return newnode
5.小岛数量【medium】
- def numIslands(self, grid: List[List[str]]) -> int:
- count = 0
- # 按数组顺序扫描
- for i in range(0, len(grid)):
- for j in range(0, len(grid[0])):
- if grid[i][j] == "1" and self.dfs(grid, i, j) >= 1:
- count += 1
- return count
-
- def dfs(self, grid: List[List[str]], i: int, j: int) -> int:
- if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]):
- return 0
- if grid[i][j] == "1":
- grid[i][j] = "0"
- # 将grid列表传入函数与(对象一样)属于引用传递,访问后改值相当于列表自带访问记录功能
- return self.dfs(grid, i-1, j) + self.dfs(grid, i, j-1) +\
- self.dfs(grid, i+1, j) + self.dfs(grid, i, j+1) + 1
- return 0
6.求条状图中的最大矩形面积【单调栈hard】
- def largestRectangleArea(self, heights: List[int]) -> int:
- # 1.采用宽度法,选取左右点固定区间,直接取高度,O(n2)
- # 2.采用高度法,对于每根柱子求取最大宽度
- # 固定高度,求宽度,即找左右侧:
- # 左侧比当前高度低的第一根柱子;右侧比当前高度低的第一根柱子
- res, istack = 0, []
- # 在矩形中加入左右哨兵以求宽度
- heights = [0] + heights + [0]
- for i in range(len(heights)):
- # 每次入栈,必须保证矩形高度为递增的
- while istack and heights[istack[-1]] > heights[i]:
- last= istack.pop()
- res = max(res, heights[last]*(i - 1 - istack[-1]))
- istack.append(i)
- return res
队列
- class MyQueue:
- def __init__(self):
- self.prestack = []
- self.poststack = []
-
- def push(self, x: int) -> None:
- while len(self.poststack) != 0:
- self.prestack.append(self.poststack.pop())
- self.prestack.append(x)
-
- def pop(self) -> int:
- while self.prestack:
- self.poststack.append(self.prestack.pop())
- if self.poststack:
- return self.poststack.pop()
- return -1
-
-
- def peek(self) -> int:
- while self.prestack:
- self.poststack.append(self.prestack.pop())
- if self.poststack:
- return self.poststack[-1]
- return -1
-
- def empty(self) -> bool:
- if not self.prestack and not self.poststack:
- return True
- return False
2.二叉树层次遍历
- def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
- # 根据广度优先搜索,从外部向内包围
- if not matrix:
- return matrix
- row, col = len(matrix), len(matrix[0])
- iqueue = []
- for i in range(row):
- for j in range(col):
- # 从外包围,先将外围入队
- if matrix[i][j] == 0:
- iqueue.append([i,j])
- # 直接用值(-1)区分需要修改的点
- else:
- matrix[i][j] = -1
- while len(iqueue) != 0:
- point_i, point_j = iqueue[0][0], iqueue[0][1]
- iqueue = iqueue[1:]
- newpoint = [[point_i-1, point_j], [point_i+1, point_j], [point_i, point_j-1], [point_i, point_j+1]]
- for n in newpoint:
- ii, jj = n[0], n[1]
- # 修改过的点为下一层入队点
- if ii >= 0 and ii < row and jj >= 0 and jj < col and matrix[ii][jj] == -1:
- matrix[ii][jj] = matrix[point_i][point_j] + 1
- iqueue.append([ii, jj])
- return matrix
- def singleNumber(self, nums: List[int]) -> int:
- res = 0
- for n in nums:
- res = res ^ n
- return res
2.3次中找1次:【异或、与、非的组合】
- def singleNumber(self, nums: List[int]) -> int:
- once, twice = 0, 0
- # n,once,twice
- # 0 0 0
- # 0 1 0
- # 0 0 1
- # 1 0 0
- # 1 1 0
- # 1 0 1
- # 对于n=1而言,3个1最终仍使once=0,实现3个数的位运算保证
- for n in nums:
- once = once ^ n & ~twice
- twice = twice ^ n & ~once
- return once
3.2次中找2个1次:
- def singleNumber(self, nums: List[int]) -> List[int]:
- # 1.求x和y的异或值。
- # 2.求这个异或值最右位的1
- # 3.找出x和y中是谁造成了这个最右位的1,以分离x和y
- res = 0
- for n in nums:
- res ^= n
- # res = x ^ y
- # 取最右一位的1:res&(~res + 1)、res&(-res)、res&(res-1)^res
- lastbit = (res&(res-1))^res
- x = 0
- for n in nums:
- if n & lastbit != 0:
- x ^= n
- return [x, res^x]
计算二进制:
1.计算二进制中1的个数:
- def hammingWeight(self, n: int) -> int:
- count = 0
- while n != 0:
- # 获取最后一位判断
- if n & (-n) == 1:
- count += 1
- n = n >> 1
- return count
2.反转32位无符号整数二进制
- def reverseBits(self, n: int) -> int:
- res = 0
- for i in range(32):
- res = res << 1
- # 获取最后一位判断
- if n & 1 == 1:
- res += 1
- n = n >> 1
- return res
3.求区间数二进制的与值
- def rangeBitwiseAnd(self, m: int, n: int) -> int:
- # 因为相邻的两个数必有1~2位不相同的位置,可以找规律:
- # 100100
- # 100101
- # 100110
- # 100111
- # 101000
- # 因为m与n的相同前缀后分别为0,1(SSS0XXX,SSS1XXX)
- # 通过m与n的不断舍取得到相同前缀即可
- count = 0
- while m != n:
- m = m >> 1
- n = n >> 1
- count += 1
- # 得到相同前缀,将末尾0补足
- return m << count
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。