剑指offer python解题

it2022-05-05  238

文章目录

回溯法67 机器人的运动范围66 矩阵中的路径 栈和队列65 滑动窗口的最大值 21 包含min函数的栈22 栈的压入和弹出序列 二叉树58 二叉树的下一个结点59 对称二叉树60 二叉树打印多行61 之字形打印二叉树62 序列化二叉树63 二叉搜索树的第K个结点50 二叉树的最低公共祖先39 二叉树的深度判断是不是平衡二叉树19 二叉树的镜像23 从上往下打印二叉树24 二叉搜索树的后续遍历25 二叉树中和为某一值的路径27 二叉搜索树与双向链表18 树的子结构6 重建二叉树 链表56 链表中环的入口结点57 删除链表中重复的结点45 圆圈中最后剩下的数字37 两个链表的第一个公共结点17 合并两个排序的链表 数组51 数组中重复的数字52 构建乘积数组38 数字在排序数组中出现的次数40 数组中出现一次的数字41 和为s的两个数43 骰子点数出现的概率29 数组中出现超过一半的数字30 最小的k个数31 连续子数组的最大和36 数组中的逆序对14 调整奇偶数 奇数位于偶数前边20 顺时针打印矩阵8 旋转数组的最小值 字符串53 正则表达式的匹配54 表示数值的字符串49 字符串转换为整数42 翻转单词顺序左旋转字符串32 1到n整数中1出现的次数33 把数排成最小的数34 丑数35 第一个只出现一次的字符28 字符串的全排列 数值11 数值的整数次方

回溯法

67 机器人的运动范围

题目描述 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

解题思路

设置visited矩阵记录每一个格子的访问状态。访问过设置为1,为访问过设置0.递归实现回溯。依次访问当前位置的上下左右的格子。 # -*- coding:utf-8 -*- import sys class Solution: def movingCount(self, threshold, rows, cols): # write code here # 记录每个格子的状态 if rows < 0 and cols < 0: return False visited = [0] * (rows * cols) count = self.calCount(threshold, rows, cols, 0, 0, visited) return count def calCount(self, threshold, rows, cols, row, col, visited): count = 0 if self.check(threshold, rows, cols, row, col, visited): visited[row * cols + col] = True count = 1 + self.calCount(threshold, rows, cols, row-1, col, visited) \ + self.calCount(threshold, rows, cols, row+1, col, visited) \ + self.calCount(threshold, rows, cols, row, col+1, visited) \ + self.calCount(threshold, rows, cols, row, col-1, visited) return count def check(self, threshold, rows, cols, row, col, visited): if 0 <= row < rows and 0 <= col < cols and visited[row * cols + col] == 0 \ and self.getSum(row) + self.getSum(col) <= threshold: return True return False def getSum(self, digit): res = 0 while digit > 0: res += digit % 10 digit //= 10 return res if __name__ == '__main__': arr = sys.stdin.readline().strip().split(' ') threshold, rows, cols = [int(x) for x in arr] count = Solution().movingCount(threshold, rows, cols) print(count)

66 矩阵中的路径

题目描述 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。 解题思路

设置visited矩阵记录每一个格子的访问状态。访问过设置为1,为访问过设置0.index 记录path的元素, 回溯法寻找匹配的元素。如果当前元素符合,寻找当前元素的四周元素。如果没有找到, index-1回溯到前一个位置。 # -*- coding:utf-8 -*- class Solution: def hasPath(self, matrix, rows, cols, path): # write code here if matrix is None and rows <= 0 and cols <= 0: return False visited = [0] * (rows * cols) pathindex = 0 for row in range(rows): for col in range(cols): if self.hasPathCore(matrix, rows, cols, row, col, path, pathindex, visited): return True return False def hasPathCore(self, matrix, rows, cols, row, col, path, pathindex, visited): haspath = False length = len(path) if pathindex == length: return True if rows > row >= 0 and cols > col >= 0 and visited[row * cols + col] == 0 \ and matrix[row * cols + col] == path[pathindex]: pathindex += 1 visited[row * cols + col] = 1 haspath = self.hasPathCore(matrix, rows, cols, row - 1, col, path, pathindex, visited) or \ self.hasPathCore(matrix, rows, cols, row + 1, col, path, pathindex, visited) or \ self.hasPathCore(matrix, rows, cols, row, col - 1, path, pathindex, visited) or \ self.hasPathCore(matrix, rows, cols, row, col + 1, path, pathindex, visited) if not haspath: pathindex -= 1 visited[row * cols + col] = 0 return haspath

栈和队列

65 滑动窗口的最大值

题目描述 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。 解题思路

设置一个两头都能进出的数据结构,python里边的list符合。存储元素的下标而非元素值,目的是好判断是否在窗口中。与当前元素下标差值大于size的都应该滑出窗口。判断当前元素和栈内元素的大小,大于栈尾部元素,尾部元素出栈。 class Solution: def maxInWindows(self, num, size): # write code here if num is None or size <= 0: return [] dequeen = [] windows = [] for idx, val in enumerate(num): if dequeen is []: dequeen.append(idx) if idx - dequeen[0] >= size: dequeen.pop(0) while dequeen is not [] and val >= num[dequeen[-1]]: dequeen.pop() dequeen.append(idx) if idx >= size - 1: windows.append(num[dequeen[0]]) return windows

21 包含min函数的栈

######################################################################### # 21 包含min函数的栈 ######################################################################### # 另外用一个辅助栈存储最小的元素 # 注意判断栈是否为空 # -*- coding:utf-8 -*- class Solution: def __init__(self): self.stack = [] self.min_stack = [] def push(self, node): self.stack.append(node) if self.min_stack == []: self.min_stack.append(node) else: self.min_stack.append(min(node, self.min_stack[-1])) def pop(self): if self.stack != [] and self.min_stack != []: self.min_stack.pop() return self.stack.pop() def top(self): if self.stack != []: return self.stack[-1] def min(self): if self.min_stack != []: return self.min_stack[-1]

22 栈的压入和弹出序列

######################################################################### # 22 栈的压入和弹出序列 ######################################################################### # 利用辅助栈,判断辅助栈最后能否全部弹出 # -*- coding:utf-8 -*- class Solution: def IsPopOrder(self, pushV, popV): # write code here if pushV == None and popV == None: return True if pushV == None or popV == None: return False stack = [] for val in pushV: stack.append(val) while stack != [] and stack[-1] == popV[0]: stack.pop() popV.pop(0) return True if stack == [] else False

二叉树

58 二叉树的下一个结点

题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 解题思路

中序遍历是左根右。如果这个结点有右子树,下一个结点就是右子树的最左结点。如果这个结点没有右子树,父节点存在,是父节点的左子结点,那么下一个结点就是此父节点,如果不是父节点的左子节点,向上遍历找到一个结点是它父节点的左子节点,此节点的父节点就是下一个结点。 class Solution: def GetNext(self, pNode): # write code here if pNode == None: return None if pNode.right: right = pNode.right while right.left != None: right = right.left return right elif pNode.next != None: parent = pNode.next if pNode == parent.left: return parent else: curNode = pNode while parent != None and curNode == parent.right: curNode = parent parent = parent.next return parent return None

59 对称二叉树

题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 解题思路 前序遍历: 根左右 自定义反前序遍历: 根右左 只要两个遍历结果一样,就是对称二叉树。也就是两个树,根节点相等,root1的左子树与oot2 的右子树对称,root1的右子树与oot2 的左子树对称,结果就是True

class Solution: def isSymmetrical(self, pRoot): # write code here return self.isSymmetricalCore(pRoot, pRoot) def isSymmetricalCore(self, root1, root2): if root1 == None and root2 == None: return True if root1 == None or root2 == None: return False if root1.val != root2.val: return False return self.isSymmetricalCore(root1.left, root2.right) and \ self.isSymmetricalCore(root1.right, root2.left)

60 二叉树打印多行

题目描述 从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。 解题思路 层次遍历,另开一个存储空间存储每一层的数值。

# -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: # 返回二维列表[[1,2],[4,5]] def Print(self, pRoot): # write code here if pRoot == None: return [] res = [] queen = [pRoot] while queen: cur = [] size = len(queen) for _ in range(size): root = queen.pop(0) cur.append(root.val) if root.left: queen.append(root.left) if root.right: queen.append(root.right) res.append(cur) return res

61 之字形打印二叉树

题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。 解题思路 定义两个栈,当前位置是奇数层时,先存储当前结点的左结点在存右结点到另一个栈中。偶数层时相反。

class Solution: def Print(self, pRoot): # write code here if pRoot == None: return [] stack_odd = [] stack_even = [] res = [] stack_odd.append(pRoot) while stack_odd or stack_even: cur = [] while stack_odd: root = stack_odd.pop() cur.append(root.val) if root.left: stack_even.append(root.left) if root.right: stack_even.append(root.right) if cur: res.append(cur) cur = [] while stack_even: root = stack_even.pop() cur.append(root.val) if root.right: stack_odd.append(root.right) if root.left: stack_odd.append(root.left) if cur: res.append(cur) return res

62 序列化二叉树

题目描述 请实现两个函数,分别用来序列化和反序列化二叉树 解题思路 前序遍历序列化,将空值记录成特殊的符号。

class Solution: def Serialize(self, root): # write code here if root == None: return "#" return str(root.val) + ',' + self.Serialize(root.left) + ',' + self.Serialize(root.right) def Deserialize(self, s): # write code here lis = s.split(',') return self.DeserializeTree(lis) def DeserializeTree(self, lis): if lis == []: return None val = lis.pop(0) root = None if val != '#': root = TreeNode(int(val)) root.left = self.DeserializeTree(lis) root.right = self.DeserializeTree(lis) return root

63 二叉搜索树的第K个结点

######################################################################### # 63 二叉搜索树的第K个结点 ######################################################################### # 中序遍历 返回第K个 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: # 返回对应节点TreeNode def KthNode(self, pRoot, k): # write code here if pRoot == None: return None stack = [] res = [] cur = pRoot while stack or cur: while cur: stack.append(cur) cur = cur.left cur = stack.pop() res.append(cur) cur = cur.right print(len(res)) if len(res) == k: return res[k-1] if k > len(res): return None

50 二叉树的最低公共祖先

######################################################################### # 50 二叉树的最低公共祖先 ######################################################################### # (1)二叉搜索树的最低公共祖先 # 判断结点是与根结点的大小关系,都小于根就递归搜索左子树, 找到返回。 # 如果都大于根就递归右子树, 找到返回结点 # 如果不满足上述两个条件,返回根节点 # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution(object): def lowestCommonAncestor(self, root, p, q): """ :type root: TreeNode :type p: TreeNode :type q: TreeNode :rtype: TreeNode """ if root == None: return None if root != None and root == p or root == q: return root if root.val > p.val and root.val > q.val: left = self.lowestCommonAncestor(root.left, p, q) if left: return left elif root.val < p.val and root.val < q.val: right = self.lowestCommonAncestor(root.right, p, q) if right: return right else: return root # (2) 有父节点的最低公共祖先 # 有父节点的二叉树相当于一个双向链表,等价于寻找两个链表的第一个公共结点 class Solution(object): def lowestCommonAncestor(self, root, p, q): """ :type root: TreeNode :type p: TreeNode :type q: TreeNode :rtype: TreeNode """ if root == None: return None if not p or not q: return None if p == q: return p depth = lambda node: depth(node.parent) + 1 if node else 0 depth_p = depth(p) depth_q = depth(q) minDepth = min(depth_p, depth_q) for i in range(depth_p - minDepth): p = p.parent for i in range(depth_q - minDepth): q = q.parent while p and q: if p == q: return p else: p = p.parent q = q.parent return None # (3) 普通二叉树的最低公共祖先 # 分为三种情况,一是都在左边,二是都在右边,三是左右都有 class Solution(object): def lowestCommonAncestor(self, root, p, q): if root == None: return None if root != None and root == p or root == q: return root left = self.lowestCommonAncestor(root.left, p, q) right = self.lowestCommonAncestor(root.right, p, q) if left and right: return root elif left != None: return left elif right != None: return right

39 二叉树的深度

######################################################################### # 39 二叉树的深度 ######################################################################### # 递归求解左右子树的深度,二者中较大的加1 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def TreeDepth(self, pRoot): # write code here if pRoot == None: return 0 left = self.TreeDepth(pRoot.left) right = self.TreeDepth(pRoot.right) return max(left, right) +1

判断是不是平衡二叉树

# 判断是不是平衡二叉树 # 方法1:直接求出左右的深度 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def TreeDepth(self, pRoot): # write code here if pRoot == None: return 0 left = self.TreeDepth(pRoot.left) right = self.TreeDepth(pRoot.right) return max(left, right) + 1 def IsBalanced_Solution(self, pRoot): # write code here if pRoot == None: return None left = self.TreeDepth(pRoot.left) right = self.TreeDepth(pRoot.right) if abs(left - right) <= 1: return True return False # 方法2:采用深度优先搜索的后序遍历,先看左右子树是否平衡,这样不用重复遍历左右结点。 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def DFS(self, root): if root == None: return 0 left = self.DFS(root.lef) if left == -1: return -1 right = self.DFS(root.right) if right == -1: return -1 if abs(left - right) > 1: return -1 return max(left, right) + 1 def IsBalanced_Solution(self, pRoot): # write code here return self.DFS(pRoot) != -1

19 二叉树的镜像

######################################################################### # 19 二叉树的镜像 ######################################################################### # 前序遍历 交换左右结点 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: # 返回镜像树的根节点 def Mirror(self, root): # write code here if root == None: return None tmp = root.left root.left = root.right root.right = tmp if root.left != None: self.Mirror(root.left) if root.right != None: self.Mirror(root.right)

23 从上往下打印二叉树

######################################################################### # 23 从上往下打印二叉树 ######################################################################### # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: # 返回从上到下每个节点值列表,例:[1,2,3] def PrintFromTopToBottom(self, root): if root == None: return [] queen = [root] res = [] while queen != None: root = queen.pop(0) res.append(root.val) if root.left != None: queen.append(root.left) if root.right != None: queen.append(root.right) return res

24 二叉搜索树的后续遍历

######################################################################### # 24 二叉搜索树的后续遍历 ######################################################################### # -*- coding:utf-8 -*- class Solution: def VerifySquenceOfBST(self, sequence): # write code here if sequence == []: return False if len(sequence) == 1: return True length = len(sequence) root = sequence[-1] i = 0 while sequence[i] < root: i += 1 for j in range(i, length - 1): if sequence[j] < root: return False left = True right = True if i > 0: left = self.VerifySquenceOfBST(sequence[:i]) if length - i - 1 > 0: right = self.VerifySquenceOfBST(sequence[i:length - 1]) return left and right

25 二叉树中和为某一值的路径

######################################################################### # 25 二叉树中和为某一值的路径 ######################################################################### # 递归算法 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: # 返回二维列表,内部每个列表表示找到的路径 def FindPath(self, root, expectNumber): # write code here if root == None: return [] res = [] path = [] self.FindPathCore(root, expectNumber, res, path) return res def FindPathCore(self, root, target, res, path): if root == None: return path.append(root.val) if root.val == target and root.left == None and root.right == None: res.append(path[:]) if root.left != None: self.FindPathCore(root.left, target - root.val, res, path) if root.right != None: self.FindPathCore(root.right, target - root.val, res, path) path.pop()

27 二叉搜索树与双向链表

######################################################################### # 27 二叉搜索树与双向链表 ######################################################################### # 利用中序遍历 左根右 # 左子树的最右节点 --根节点 -- 右子树的最左结点 相连接 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def Convert(self, pRootOfTree): # write code here if pRootOfTree == None: return None self.Convert(pRootOfTree.left) if pRootOfTree.left != None: left = pRootOfTree.left while left.right: left = left.right left.right, pRootOfTree.left = pRootOfTree, left self.Convert(pRootOfTree.right) if pRootOfTree.right != None: right = pRootOfTree.right while right.left: right = right.left right.left, pRootOfTree.right = pRootOfTree, right while pRootOfTree.left: pRootOfTree = pRootOfTree.left return pRootOfTree

18 树的子结构

######################################################################### # 18 树的子结构 ######################################################################### # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def HasSubtree(self, pRoot1, pRoot2): # write code here if pRoot1 == None or pRoot2 == None: return False result = False if pRoot1.val == pRoot2.val: result = self.helper(pRoot1,pRoot2) or \ self.HasSubtree(pRoot1.left, pRoot2) or \ self.HasSubtree(pRoot1.right, pRoot2) return result def helper(self, root1, root2): if root2 == None: return True if root1 == None: return False if root1.val != root2.val: return False return self.helper(root1.left, root2.left) and self.helper(root1.right, root2.right)

6 重建二叉树

######################################################################### # 6 重建二叉树 ######################################################################### # 前提条件 前序遍历或者中序遍历存在 # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: # 返回构造的TreeNode根节点 def reConstructBinaryTree(self, pre, tin): # write code here if pre == None or tin == None: return None root = None if pre: rootVal = pre[0] rootIndex = tin.index(rootVal) root = TreeNode(rootVal) root.left = self.reConstructBinaryTree(pre[1: rootIndex + 1], tin[: rootIndex]) root.right = self.reConstructBinaryTree(pre[rootIndex + 1:], tin[rootIndex + 1:]) return root

链表

56 链表中环的入口结点

######################################################################### # 56 链表中环的入口结点 ######################################################################### # 快慢指针先找到环 然后找到环的结点 # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def EntryNodeOfLoop(self, pHead): # write code here if pHead == None or pHead.next == None or pHead.next.next == None: return None fast = pHead slow = pHead while fast.next and fast.next.next and slow != fast: fast = fast.next.next slow = slow.next if slow == fast: slow = pHead while fast != slow: slow = slow.next fast = fast.next return slow return None

57 删除链表中重复的结点

######################################################################### # 57 删除链表中重复的结点 ######################################################################### # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def deleteDuplication(self, pHead): # write code here if pHead == None or pHead.next == None: return pHead pre = ListNode(0) pre.next = pHead post = pre cur = pHead while cur and cur.next: if cur.next.val != cur.val: cur = cur.next post = post.next else: val = cur.val while cur and cur.val == val: cur = cur.next post.next = cur return pre.next

45 圆圈中最后剩下的数字

######################################################################### # 45 圆圈中最后剩下的数字 ######################################################################### # -*- coding:utf-8 -*- class ListNode: def __init__(self, val): self.val = val self.next = None class Solution: def LastRemaining_Solution(self, n, m): if n == 0 or m == 0: return -1 head = self.build_circle(n) step = 0 while head: step += 1 if step == m: if head.next != head: head.val = head.next.val head.next = head.next.next else: return head.val step = 0 else: head = head.next # write code here def build_circle(self, n): tmp = None head = None for x in range(n): if tmp == None: tmp = ListNode(x) head = tmp else: tmp.next = ListNode(x) tmp = tmp.next tmp.next = head return head # 约瑟夫环 # f(n,m ) = 0 n = 1 # f(n-1, m) + m % n n > 1 class Solution: def LastRemaining_Solution(self, n, m): if n == 0 or m == 0: return -1 if n == 1: return 0 res = 0 for i in range(1, n + 1): res = (res + m) % i return res

37 两个链表的第一个公共结点

######################################################################### # 37 两个链表的第一个公共结点 ######################################################################### # 计算两个链表的长度,长链表先走diff步然后两个链表一起走,相交点就是第一个公共结点 # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def FindFirstCommonNode(self, pHead1, pHead2): # write code here if pHead1 == None or pHead2 == None: return None length1 = self.getLength(pHead1) length2 = self.getLength(pHead2) diff = length1 - length2 headlong = pHead1 headshort = pHead2 if length2 > length1: diff = length2 - length1 headlong = pHead2 headshort = pHead1 while diff > 0: headlong = headlong.next diff -= 1 while headlong != None and headshort != None and headlong != headshort: headlong = headlong.next headshort = headshort.next return headlong def getLength(self, head): length = 0 while head: length += 1 head = head.next return length # 更为简单的方法是P1和P2同时向后移动,如果到了链表的最后结点,就接到另一个链表的头部 # 直到两者相遇就是公共结点 class Solution: def FindFirstCommonNode(self, pHead1, pHead2): if pHead1 == None or pHead2 == None: return None p1 = pHead1 p2 = pHead2 while p1 != p2: p1 = p1.next if p1 != None else pHead2 p2 = p2.next if p2 != None else pHead1 return p1

17 合并两个排序的链表

######################################################################### # 17 合并两个排序的链表 ######################################################################### # 初始化一个头结点ret与mergehead指向同一个位置。 # 比较两个链表的大小,next指向小的链表,然后merge移动到next 直到遍历完一个链表 # 最后拼接起来不为空的链表 # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: # 返回合并后列表 def Merge(self, pHead1, pHead2): # write code here if pHead1 == None: return pHead2 if pHead2 == None: return pHead1 mergeHead = ListNode(-1) ret = mergeHead while pHead1 and pHead2: if pHead1.val <= pHead2.val: mergeHead.next = pHead1 pHead1 = pHead1.next else: mergeHead.next = pHead2 pHead2 = pHead2.next mergeHead = mergeHead.next if pHead1 != None: mergeHead.next = pHead1 if pHead2 != None: mergeHead.next = pHead2 return ret.next

数组

51 数组中重复的数字

######################################################################### # 51 数组中重复的数字 ######################################################################### # -*- coding:utf-8 -*- class Solution: # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0] # 函数返回True/False def duplicate(self, numbers, duplication): # write code here if numbers == []: return False for i in range(len(numbers)): while numbers[i] != i: if numbers[i] == numbers[numbers[i]]: duplication[0] = numbers[i] return True #numbers[numbers[i]], numbers[i] = numbers[i], numbers[numbers[i]] tmp = numbers[i] numbers[i] = numbers[tmp] numbers[tmp] = tmp return False

52 构建乘积数组

######################################################################### # 52 构建乘积数组 ######################################################################### # 将数组B 分成两段,C = A[0]* ... A[i-1] D = A[i+1:] *...A[n] # 所以 C[i] = C[i-1] * A[i-1]; D[i] = D[i+1]*A[i+1] # -*- coding:utf-8 -*- class Solution: def multiply(self, A): # write code here if A == []: return [] B = [1] * len(A) c = 1 for i in range(len(A)): d = 1 c *= A[i-1] if i > 0 else c for j in (A[i+1:]): d *= j B[i] = c*d return B

38 数字在排序数组中出现的次数

######################################################################### # 38 数字在排序数组中出现的次数 ######################################################################### # 排序数组用二分查找的变体 # 分别找到数字的开始和结束位置。 # 1. 找到开始位置。 二分查找的中间值 如果小于k,查找后半段 low=mid+1; # 如果大于或者等于k,都查找前半段 high=mid # 终点位置同理 # -*- coding:utf-8 -*- class Solution: def GetNumberOfK(self, data, k): if data == []: return 0 # write code here low = 0 high = len(data) - 1 while high > low: mid = (low + high) // 2 if data[mid] < k: low = mid + 1 # 如果当前值大于或者等于k都直接向前半段搜索,知道找到第一个K else: high = mid if data[low] != k: return 0 first = low high = len(data) - 1 while high > low: mid = (low + high) // 2 + 1 if data[mid] > k: high = mid - 1 else: low = mid end = high return end -first + 1

40 数组中出现一次的数字

######################################################################### # 40 数组中出现一次的数字 ######################################################################### # 所有数字异或后肯定有一位是1,按照这一位是1划分数组,然后在每一组中在分别找只出现一次的数字 # -*- coding:utf-8 -*- class Solution: # 返回[a,b] 其中ab是出现一次的两个数字 def FindNumsAppearOnce(self, array): # write code here if array == []: return [] res = array[0] for num in array[1:]: res ^= num mask = 1 while res & mask != 1: mask <<= 1 num1 = 0 num2 = 0 for x in array: # 这一位是0 相与为0, 划分为两组 if x & mask == 0: num1 ^= x else: num2 ^= x return [num1, num2]

41 和为s的两个数

######################################################################### # 41 和为s的两个数 ######################################################################### # 递增序列中寻找和为sde的两个数字,用两个指针前后搜索O(n) # -*- coding:utf-8 -*- class Solution: def FindNumbersWithSum(self, array, tsum): # write code here if array == []: return [] left = 0 right = len(array) - 1 while left < right: if array[left] + array[right] == tsum: return [array[left], array[right]] elif array[left] + array[right] > tsum: right -= 1 else: left += 1 return [] # 和为s的连续正数序列 # -*- coding:utf-8 -*- class Solution: def FindContinuousSequence(self, tsum): # write code here if tsum <= 1: return [] small = 1 big = 2 ret = [] cur_sum = small + big while small <= (tsum + 1) // 2: # 如果此时相等,记录结果并且big继续加大, 寻找下一组结果 if cur_sum == tsum: res = list(range(small, big+1)) ret.append(res) big += 1 cur_sum += big # 如果大于tsum,加大small的值 elif cur_sum > tsum: cur_sum -= small small += 1 # 如果小于tsum 加大big else: big += 1 cur_sum += big return ret

43 骰子点数出现的概率

######################################################################### # 43 骰子点数出现的概率 ######################################################################### # 骰子出现的点数的概率,用动态规划的思想 # 设dp为n * 6n的二维数组,n代表n个骰子,6n代表最大和为6n # 递推公式为f(n, sum) = f(n-1, sum-1)+ f(n-1, sum-2) +f(n-1, sum-3)+f(n-1, sum-4)+f(n-1, sum-5)+f(n-1, sum-6) # 这个四舍五入的真是太费劲了!!!! from decimal import * class Solution: def dicesSum(self, n): g_maxvalue = 6 dp = [[0] * (6 * n) for _ in range(n)] # 初始化n=1时的情况 for i in range(g_maxvalue): dp[0][i] = 1 # n=2 开始 for i in range(1, n): # i个骰子至少得到i个点(都是1),至多6*i个点(都是6) for j in range(i, 6 * (i + 1)): # 上一个骰子可能出现的点数为1-6 for k in range(1, 6 + 1): if j >= k: dp[i][j] += dp[i - 1][j - k] total = 6.0 ** n res = [(dp[n - 1][i] / total) for i in range(6 * n)] ret = [] for i in range(n - 1, 6 * n): ret.append([i + 1, float(Decimal(str(res[i])).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP))]) return ret

29 数组中出现超过一半的数字

######################################################################### # 29 数组中出现超过一半的数字 ######################################################################### # 方法1:从头遍历一遍,选定一个数字,如果相同count+1.不同减去1;如果count为0了,重新选择一个数字。 # 最后的结果就是最后一次把结果设置为1的数字。 # -*- coding:utf-8 -*- class Solution: def MoreThanHalfNum_Solution(self, numbers): # write code here if numbers == 0: return 0 count = 1 res = numbers[0] for i in range(1, len(numbers)): if count == 0: res = numbers[i] if numbers[i] == res: count += 1 else: count -= 1 count = 0 for x in numbers: if x == res: count += 1 if count > len(numbers) // 2: return res else: return 0 # 方法2 利用Partition函数排序,如果存在,中间位置的数字就是结果 class Solution: def MoreThanHalfNum_Solution(self, numbers): if numbers == []: return 0 middle = (len(numbers)) // 2 left = 0 right = len(numbers) - 1 index = self.Partition(numbers, left, right) while index != middle: if index > middle: right = index - 1 index = self.Partition(numbers, left, right) elif index < middle: left = index + 1 index = self.Partition(numbers, left, right) count = 0 for x in numbers: if x == numbers[middle]: count += 1 if count > middle: return numbers[index] else: return 0 def Partition(self, nums, begin, end): left = begin + 1 right = end index = begin while left <= right: if nums[left] > nums[index] and nums[right] < nums[index]: nums[left], nums[right] = nums[right], nums[left] if nums[left] <= nums[index]: left += 1 if nums[right] >= nums[index]: right -= 1 nums[index], nums[right] = nums[right], nums[index] return right

30 最小的k个数

######################################################################### # 30 最小的k个数 ######################################################################### # 方法1: Partition函数 # -*- coding:utf-8 -*- class Solution: def GetLeastNumbers_Solution(self, tinput, k): # write code here if tinput == []: return [] if k <= 0 or k > len(tinput): return [] if k == len(tinput): return self.quicksort(tinput, 0, k - 1) begin = 0 end = len(tinput) - 1 index = self.Partition(tinput, begin, end) while index != k: if index > k: end = index - 1 index = self.Partition(tinput, begin, end) elif index < k: begin = index + 1 index = self.Partition(tinput, begin, end) res = tinput[:index] return self.quicksort(res, 0, len(res) - 1) def Partition(self, nums, begin, end): index = begin left = begin + 1 right = end while left <= right: if nums[left] > nums[index] and nums[right] < nums[index]: nums[left], nums[right] = nums[right], nums[left] if nums[left] <= nums[index]: left += 1 if nums[right] >= nums[index]: right -= 1 nums[index], nums[right] = nums[right], nums[index] return right def quicksort(self, nums, left, right): if left < right: index = self.Partition(nums, left, right) self.quicksort(nums, left, index - 1) self.quicksort(nums, index + 1, right) return nums import heapq class Solution: def GetLeastNumbers_Solution(self, tinput, k): if tinput == []: return [] if k <= 0 or k > len(tinput): return [] if k == len(tinput): res = sorted(tinput) return res res = [] # 取x的相反数建立最小堆,res的第一个值是最小的,也就是-res[0]是最大的 for x in tinput: if len(res) < k: res.append(-x) heapq.heapify(res) for x in tinput[k:]: max_val = -res[0] if x < max_val: heapq.heappop(res) heapq.heappush(res, -x) return sorted([-x for x in res])

31 连续子数组的最大和

######################################################################### # 31 连续子数组的最大和 ######################################################################### # -*- coding:utf-8 -*- class Solution: def FindGreatestSumOfSubArray(self, array): # write code here if array == []: return None if len(array) == 1: return array[0] dp = [-float('inf')] * len(array) for i in range(len(array)): if i == 0: dp[i] = array[0] if dp[i-1] <= 0: dp[i] = array[i] else: dp[i] = dp[i-1] + array[i] return max(dp)

36 数组中的逆序对

######################################################################### # 36 数组中的逆序对 ######################################################################### # 采用归并的方法 # 循环将数组一分为二, 直到数组为两个长度为1的数组,在进行合并和排序 # 比如 7564 ——> 75 64 ——>7 5 和 6 4 # 合并相邻数组7 5 存在一个逆序对记录count+1 并且排序为5 7 避免之后重复统计 # -*- coding:utf-8 -*- from copy import deepcopy class Solution: def InversePairs(self, data): # write code here; if data == []: return 0 start = 0 end = len(data) - 1 copy = deepcopy(data) count = self.InverseaPairsCore(data, copy, start, end) return count % 1000000007 def InverseaPairsCore(self, data, copy, start, end): if start == end: copy[start] = data[start] return 0 length = (end - start) // 2 left = self.InverseaPairsCore(data, copy, start, start + length) right = self.InverseaPairsCore(data, copy, start + length + 1, end) i = start + length j = end count = 0 copyindex = end while i >= start and j > start+length: if data[i] > data[j]: copy[copyindex] = data[i] copyindex -= 1 i -= 1 count += j - (start + length) else: copy[copyindex] = data[j] copyindex -= 1 j -= 1 while i >= start: copy[copyindex] = data[i] copyindex -= 1 i -= 1 while j >= start + length + 1: copy[copyindex] = data[j] copyindex -= 1 j -= 1 s = start while s <= end: data[s] = copy[s] s += 1 return left + right + count

14 调整奇偶数 奇数位于偶数前边

######################################################################### # 14 调整奇偶数 奇数位于偶数前边 ######################################################################### # -*- coding:utf-8 -*- class Solution: def reOrderArray(self, array): # write code here if array == None: return [] left = 0 right = len(array) - 1 while left <= right: # 左边是偶数 右边是奇数 交换 if self.isEven(array[left]) and not self.isEven(array[right]): array[left], array[right] = array[right], array[left] if not self.isEven(array[left]): left += 1 if self.isEven(array[right]): right -= 1 return array def isEven(self, num): if num & 0x1 == 0: return True return False # 采用插入排序的算法 # 插入排序 从小到大排序 # 依次遍历数组中的每个元素,当插入到第 i 个位置时,前边的所有元素V[0] V[1]··· V[i-1]都已经排序完毕。 # 此时将V[i] 与前边的所有元素比较,找到插入位置,插入V[i] ,原来位置上的元素向后顺移。 def InsertSort(nums): length = len(nums) for i in range(length): key = nums[i] for j in range(i - 1, -1, -1): if nums[j] > key: nums[j + 1] = nums[j] nums[j] = key return nums # 调整奇偶数 奇数位于偶数前边 且不改变数字的前后位置 # 判断当前位置是不是奇数 如果是 遍历前边数字 如果是偶数与当前位置交换 class Solution: def reOrderArray(self, array): length = len(array) for i in range(length): if self.isOdd(array[i]): key = array[i] for j in range(i-1, -1, -1): if not self.isOdd(array[j]): array[j+1] = array[j] array[j] = key return array def isOdd(self, num): if num & 0x1 == 1: return True return False

20 顺时针打印矩阵

######################################################################### # 20 顺时针打印矩阵 ######################################################################### # -*- coding:utf-8 -*- class Solution: # matrix类型为二维列表,需要返回列表 def printMatrix(self, matrix): # write code here if matrix == None: return None def helper(r1, r2, c1, c2): for c in range(c1, c2 + 1): yield r1, c for r in range(r1 + 1, r2 + 1): yield r, c2 if r1 < r2 and c1 < c2: for c in range(c2 - 1, c1, -1): yield r2, c for r in range(r2, r1, -1): yield r, c1 r1, r2 = 0, len(matrix)-1 c1, c2 = 0, len(matrix[0])-1 res = [] while r1 <= r2 and c1 <= c2: for r, c in helper(r1, r2, c1, c2): res.append(matrix[r][c]) r1 += 1 r2 -= 1 c1 += 1 c2 -= 1 return res

8 旋转数组的最小值

######################################################################### # 8 旋转数组的最小值 ######################################################################### # -*- coding:utf-8 -*- class Solution: def minNumberInRotateArray(self, rotateArray): # write code here if rotateArray == None: return None left = 0 right = len(rotateArray) - 1 mid = left while rotateArray[left] >= rotateArray[right]: if right - left == 1: mid = right break mid = (left + right) // 2 if rotateArray[mid] >= rotateArray[left]: left = mid elif rotateArray[mid] <= rotateArray[right]: right = mid if rotateArray[mid] == rotateArray[left] and rotateArray[mid] == rotateArray[right]: return self.Inorder(rotateArray, left, right) return rotateArray[mid] def Inorder(self, nums, left, right): res = nums[left] for i in range(left, right + 1): if nums[i] < res: res = nums[i] return res

字符串

53 正则表达式的匹配

######################################################################### # 53 正则表达式匹配 ######################################################################### # 分情况讨论 1. 如果第二个正则不是*, 那么只看第一个字符即可。 # 如果S[0] == P[0] or P[0] == '.', 那么第一个匹配,S和P 同时向后移动一位 # 2. 如果第二个正则是P,情况分为三种。 # 方法2 动态规划 # dp[i][j] 分别表示s[i] 与p[j]的匹配情况 # -*- coding:utf-8 -*- class Solution: # s, pattern都是字符串 def match(self, s, pattern): # write code here memo = {} def dp(i, j): if (i, j) not in memo: # 匹配结束,如果此时遍历完s,表示匹配成功 if j == len(pattern): res = i == len(s) else: firstmatch = len(s) > i and pattern[j] in {s[i], '.'} if len(pattern) > j + 1 and pattern[j + 1] == '*': # 如果第二个是*, 匹配0个: dp(i, j+2) # 或者匹配多个 (第一个匹配且第二个为*) firstmatch and dp(s+1, j) res = dp(i, j + 2) or firstmatch and dp(i + 1, j) else: # 如果第二个不是*, 如果第一个匹配,那么s,p 同时向前一个 res = firstmatch and dp(i + 1, j + 1) memo[i, j] = res return memo[i, j] return dp(0, 0) class Solution: # s, pattern都是字符串 # 递归方法 def match(self, s, pattern): if len(s) == 0 and len(pattern) == 0: return True if len(s) != 0 and len(pattern) == 0: return False if len(pattern) > 1 and pattern[1] == '*': if len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.'): # 匹配0个 or 匹配1个 or 匹配多个 return self.match(s, pattern[2:]) \ or self.match(s[1:], pattern[2:]) \ or self.match(s[1:], pattern) else: # 如果第一个不匹配 return self.match(s, pattern[2:]) else: if len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.'): return self.match(s[1:], pattern[1:]) return False

54 表示数值的字符串

######################################################################### # 54 表示数值的字符串 ######################################################################### # -*- coding:utf-8 -*- class Solution: # s字符串 def __init__(self): self.idx = 0 self.expo = {'e', 'E'} self.sign = {'+', '-'} def isNumeric(self, s): # write code here if s == '': return False if s[self.idx] in self.sign: self.idx += 1 if self.idx == len(s): return False res = True self.scanString(s) print(self.idx) if self.idx < len(s): if s[self.idx] == '.': self.idx += 1 self.scanString(s) if self.idx < len(s) and s[self.idx] in self.expo: res = self.isExpo(s) elif s[self.idx] in self.expo: res = self.isExpo(s) else: res = False return res and self.idx == len(s) def scanString(self, s): while self.idx < len(s) and s[self.idx] >= '0' and s[self.idx] <= '9': self.idx += 1 def isExpo(self, s): if s[self.idx] not in self.expo: return False self.idx += 1 if self.idx < len(s) and s[self.idx] in self.sign: self.idx += 1 if self.idx == len(s): return False self.scanString(s) return True if self.idx == len(s) else False

49 字符串转换为整数

######################################################################### # 49 字符串转换为整数 ######################################################################### # -*- coding:utf-8 -*- class Solution: def StrToInt(self, s): # write code here s = s.strip() if len(s) == 0: return 0 if s[0] == '-': sign = -1 else: sign = 1 if s[0] in {'+', '-'}: s = s[1:] if len(s) == 0: return 0 res = 0 if not s[0].isdigit(): return 0 for x in s: if x.isdigit(): res = 10 * res + ord(x) - ord('0') else: break return 0 return max(-2**(31), min(2**31-1, sign * res))

42 翻转单词顺序

######################################################################### # 42 翻转单词顺序 ######################################################################### # 先翻转整个句子, 然后翻转每个单词 class Solution: def ReverseSentence(self, s): # write code here begin = 0 end = len(s) - 1 s = self.ReverseWord(list(s)[begin:end + 1]) begin = 0 end = 0 res = '' while end < len(s): if s[end] == ' ': reverse_word = self.ReverseWord(list(s)[begin:end]) res += reverse_word res += s[end] begin = end + 1 elif end == len(s) - 1: reverse_word = self.ReverseWord(list(s)[begin:end + 1]) res += reverse_word end += 1 return res def ReverseWord(self, s): if s == '': return '' begin = 0 end = len(s) - 1 while begin <= end: s[begin], s[end] = s[end], s[begin] begin += 1 end -= 1 return ''.join(s)

左旋转字符串

class Solution: def LeftRotateString(self, s, n): if s == '': return '' if n > len(s): return None left = self.ReverseWord(list(s[:n])) right = self.ReverseWord(list(s[n:])) res = self.ReverseWord(list(left+right)) return res def ReverseWord(self, s): begin = 0 end = len(s) - 1 while begin <= end: s[begin], s[end] = s[end], s[begin] begin += 1 end -= 1 return ''.join(s)

32 1到n整数中1出现的次数

######################################################################### # 32 1到n整数中1出现的次数 ######################################################################### # 找数字规律求解 比如21345这个数,分为1-1345和1346-21345两个阶段。 # 1346-21345 最高位的1为10000个也就是10^(n-1)个;如果最高位是1,比如12345 最高位则是2345+1=2346个1 # 剩下的四位数可以分为两段 1346-11345和11345-21345,两段中都可以选择一位为1,其余三位的选择分别有0-9 10 个数字, # 也就是2*4*10^3 # 1-1345可以递归求解 # -*- coding:utf-8 -*- class Solution: def NumberOf1Between1AndN_Solution(self, n): # write code here length = len(str(n)) first = int(str(n)[0]) if length == 0: return None if length == 1 and first == 0: return 0 if length == 1 and first > 0: return 1 # 求得最高位的1 if first > 1: numberFirst_1 = 10 ** (length - 1) else: numberFirst_1 = int(str(n)[1:]) + 1 # 求得剩下的几位数中的1 numberOther_1 = first * (length - 1) * 10 ** (length - 2) numberRecursive = self.NumberOf1Between1AndN_Solution(int(str(n)[1:])) return numberFirst_1 + numberOther_1 + numberRecursive

33 把数排成最小的数

######################################################################### # 33 把数排成最小的数 ######################################################################### # 自定义比较规则为 如果mn < nm,则定义m<n 然后按照这个规则对numbers进行排序之后拼接在一起 # -*- coding:utf-8 -*- import functools class Solution: def PrintMinNumber(self, numbers): # write code here if numbers == []: return '' if len(numbers) == 1: return str(numbers[0]) def mycmp(num1, num2): return cmp(num1 + num2, num2 + num1) nums = [str(n) for n in numbers] res = sorted(nums, mycmp) return ''.join(res)

34 丑数

######################################################################### # 34 丑数 ######################################################################### # 空间换时间。每一个丑数都是前一个丑数乘以2 3 5 得到的。 # 所以最小的丑数= min(现在最小的乘以2,3,4后的结果) # 而且对于现有的每一个丑数乘以2之后,肯定存在一个数T2, 在他之前的都小于现有的,在他之后的都会大于现有的最小丑数 # 对于3 和 5 的同理。只需要找到T2 T3 T5 即可。 # -*- coding:utf-8 -*- class Solution: def GetUglyNumber_Solution(self, index): # write code here if index <= 0: return 0 if index == 1: return 1 uglynum = [0] * index nextidx = 1 uglynum[0] = 1 p2, p3, p5 = 0, 0, 0 while nextidx < index: min_ugly = min(uglynum[p2] * 2, uglynum[p3] * 3, uglynum[p5] * 5) uglynum[nextidx] = min_ugly while uglynum[p2] * 2 <= min_ugly: p2 += 1 while uglynum[p3] * 3 <= min_ugly: p3 += 1 while uglynum[p5] * 5 <= min_ugly: p5 += 1 nextidx += 1 return uglynum[index-1]

35 第一个只出现一次的字符

######################################################################### # 35 第一个只出现一次的字符 ######################################################################### # hash表存储字符和次数,因为python里边的dict不会按照顺序存储,所以单独用一个list存储顺序 # -*- coding:utf-8 -*- class Solution: def FirstNotRepeatingChar(self, s): # write code here if s == '': return -1 dic = {} once = [] for i in range(len(s)): if s[i] not in once: once.append(i) if s[i] not in dic: dic[s[i]] = 1 else: dic[s[i]] += 1 for i in once: if dic[s[i]] == 1: return i return None

28 字符串的全排列

######################################################################### # 28 字符串的全排列 ######################################################################### # 全排列方法 字符串的全排列 八皇后问题 正方体问题 # -*- coding:utf-8 -*- class Solution: def Permutation(self, ss): if ss == '': return [] res = [] path = '' self.PermutationCore(ss, res, path) res = set(res) return sorted(list(res)) def PermutationCore(self, s, res, path): if s == '': res.append(path) else: for i in range(len(s)): self.PermutationCore(s[:i] + s[i + 1:], res, path + s[i]) # 八皇后问题 # 设置一个一维数组,num[i] = j 表示第i行皇后的位置是第j列 # i 从0-n全排列 判断是否符合要求 不同行不同列不同一对角线 # 一维数组能够保证不同行不同列 对角线是y=x+b,y1-y2 = x1-x2 代表是同一对角线 # 所以 不在同一对角线要保证 abs(nums[i] - nums[n]) != n-i and nums[i] != nums[n] class Solution(object): def solveNQueens(self, n): """ :type n: int :rtype: List[List[str]] """ if n <= 0: return '' num = [-1] * n res = [] path = [] self.Permutation(num, 0, res, path) return res def Permutation(self, num, index, res, path): if index == len(num): res.append(path) return else: for i in range(len(num)): num[index] = i if self.CheckValid(num, index): tmp = '.' * len(num) self.Permutation(num, index + 1, res, path + [tmp[:i] + 'Q' + tmp[i + 1:]]) def CheckValid(self, num, index): for i in range(index): if abs(num[i] - num[index]) == index - i or num[i] == num[index]: return False return True

数值

11 数值的整数次方

######################################################################### # 11 数值的整数次方 ################################### ###################################### # a^n = a ^(n/2) * a(n/2) 偶数 a * (n-1/2) * a(n-1/2) 奇数 # -*- coding:utf-8 -*- class Solution: def Power(self, base, exponent): # write code here if base == 1 or exponent == 0: return 1 if exponent == 1: return base if exponent < 0: return 1.0 / self.Power(base, abs(exponent)) result = self.Power(base, exponent >> 1) result *= result if exponent & 0x1 == 1: result *= base return result

最新回复(0)