题目描述1:33.二叉搜索树的后序遍历序列 难度:中等
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
5
/ \
2 6
/ \
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
解题思路:
层序遍历
Python代码:
class Solution: def verifyPostorder(self, postorder: List[int]) -> bool: if postorder is None or len(postorder) == 0: return True n = len(postorder) # 根结点 root = postorder[-1] # 在二叉搜索树中左子树的结点小于根结点 i = 0 for i in range(n): if postorder[i] > root: break # 在二叉搜索树中右子树的结点小于根结点 for j in range(i,n-1): if postorder[j] < root: return False # 判断左子树是不是二叉搜索树 left = True if i > 0: left = self.verifyPostorder(postorder[:i]) # 左闭右开 # 判断右子树是不是二叉搜索树 right = True if i < n-1: right = self.verifyPostorder(postorder[i:-1]) return left and right
题目描述2:34.二叉树中和为某一值的路径 难度:中等
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:
[
[5,4,11,2],
[5,8,4,5]
]
解题思路:
DFS + 回溯
BFS 迭代
Python代码:
#方法1codeclass Solution: def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]: res,path = [] ,[] def dfs(root,target): if not root:return [] target -= root.val path.append(root.val) if not root.left and not root.right and target == 0: res.append(path[:]) #res.append(list(path)) dfs(root.left,target) dfs(root.right,target) path.pop() dfs(root,sum) return res#方法2codeclass Solution: def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]: if not root: return [] queue = [(root, root.val, [root.val])] res = [] while queue: node, val, temp = queue.pop(0) if val == sum and not node.left and not node.right: res.append(temp) if node.left: queue.append((node.left, val + node.left.val, temp+[node.left.val])) if node.right: queue.append((node.right, val + node.right.val , temp+[node.right.val])) return res
题目描述3:35.复杂链表的复制 难度:中等
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
解题思路:
1.迭代
2.递归
Python代码:
#方法1code"""# Definition for a Node.class Node: def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None): self.val = int(x) self.next = next self.random = random"""class Solution: def copyRandomList(self, head: 'Node') -> 'Node': if not head:return dic = {} # 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射 cur = head # 构建新节点的 next 和 random 指向 while cur: dic[cur] = Node(cur.val) cur = cur.next cur =head while cur: dic[cur].next = dic.get(cur.next) dic[cur].random = dic.get(cur.random) cur = cur.next # 返回新链表的头节点 return dic[head]#方法2codeclass Solution: def copyRandomList(self, head: 'Node') -> 'Node': def dfs(head): if not head:return None if head in visited: return visited[head] #创建新结点 copy = Node(head.val) visited[head] = copy copy.next = dfs(head.next) copy.random = dfs(head.random) return copy visited = {} return dfs(head)
题目描述4:36.二叉搜索树中与双向链表 难度:中等
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
解题思路:
中序遍历
Python代码:
#方法1codeclass Solution: def treeToDoublyList(self, root: 'Node') -> 'Node': if not root:return def dfs(cur): if not cur: return dfs(cur.left) # 递归左子树 if self.pre: #修改节点引用 self.pre.right,cur.left = cur,self.pre else: #记录头节点 self.head = cur self.pre = cur #保存cur dfs(cur.right) #递归右子树 self.pre =None dfs(root) self.head.left,self.pre.right = self.pre,self.head return self.head
题目描述5:37.序列化二叉树 难度:困难
请实现两个函数,分别用来序列化和反序列化二叉树。
示例:
你可以将以下二叉树:
1
/ \
2 3
/ \
4 5
序列化为 "[1,2,3,null,null,4,5]"
解题思路:
无
Python代码:
# Definition for a binary tree node.# class TreeNode(object):# def __init__(self, x):# self.val = x# self.left = None# self.right = Noneclass Codec: def serialize(self, root): if not root: return "[]" queue = collections.deque() queue.append(root) res = [] while queue: node = queue.popleft() if node: res.append(str(node.val)) queue.append(node.left) queue.append(node.right) else: res.append("null") return '[' + ','.join(res) + ']' def deserialize(self, data): if data == "[]": return vals, i = data[1:-1].split(','), 1 root = TreeNode(int(vals[0])) queue = collections.deque() queue.append(root) while queue: node = queue.popleft() if vals[i] != "null": node.left = TreeNode(int(vals[i])) queue.append(node.left) i += 1 if vals[i] != "null": node.right = TreeNode(int(vals[i])) queue.append(node.right) i += 1 return root# Your Codec object will be instantiated and called as such:# codec = Codec()# codec.deserialize(codec.serialize(root))
题目描述6:38.字符串的排列 难度:中等
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]
解题思路:
回溯算法
Python代码:
class Solution: def permutation(self, s: str) -> List[str]: s = list(s) res = [] def dfs(x): if x == len(s): res.append(''.join(s)) #添加排列方案 return repeat = [] for i in range(x,len(s)): if s[i] in repeat:continue #重复,因此剪枝 repeat.append(s[i]) s[x],s[i] = s[i],s[x] #交换,将c[i]固定在第x位 dfs(x+1) #开始国定第x+1位字符 s[i],s[x] = s[x],s[i] #恢复交换 dfs(0) return res
题目描述7:39.数组中出现次数超过一半的数字 难度:简单
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
解题思路:
无
Python代码:
class Solution: def majorityElement(self, nums: List[int]) -> int: # nums.sort() # return nums[len(nums)//2] dicts = {} for i in nums: dicts[i] = dicts.setdefault(i,0) dicts[i] += 1 if dicts[i] > len(nums)/2: return i
题目描述8:40.最小的k个数 难度:简单
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
解题思路:
几种排序算法(待总结):快排、堆排、计数排序
Python代码:
class Solution: def getLeastNumbers(self, arr: List[int], k: int) -> List[int]: arr.sort() return arr[:k]
题目描述9:41.数据流中的中位数 难度:困难
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例 1:
输入:
["MedianFinder","addNum","addNum","findMedian","addNum","findMedian"]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]
示例 2:
输入:
["MedianFinder","addNum","findMedian","addNum","findMedian"]
[[],[2],[],[3],[]]
输出:[null,null,2.00000,null,2.50000]
解题思路:
堆排序(待总结),使用堆排序
Python代码:
class MedianFinder: def __init__(self): """ initialize your data structure here. """ self.res = [] def addNum(self, num: int) -> None: self.res.append(num) def findMedian(self) -> float: self.res.sort() if len(self.res)%2 == 1: return self.res[len(self.res)//2] else: return (self.res[len(self.res)//2]+self.res[len(self.res)//2-1])/2
题目描述10:42.连续子数组的最大和 难度:简单
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
解题思路:
动态规划求解
1.定义当前最大连续子序列和cur_sum=0,最大子序和res=nums[0]。
2.对数组进行遍历,对于nums[i],存在两种情况:
(1) 若当前最大连续子序列和cur_sum>0,说明cur_sum对后续结果有着正向增益,即能使后继结果继续增大,则继续加和:cur_sum=cur_sum+num[i]。
(2)若当前最大连续子序列和cur_sum<=0,说明cur_sum对后续结果没有增益或负向增益,即若存在更大的加和,一定是从下一元素开始,加上cur_sum,只会使结果更小。因此,令cur_sum更新为nums[i]。
更新最大子序和res=max(res,cur_sum),始终保留最大结果。
Python代码:
class Solution: def maxSubArray(self, nums: List[int]) -> int: cur_sum = 0 #当前最大连续子序列和 res = nums[0] #最大连续子序列和 for i in range(len(nums)): if cur_sum>0: cur_sum += nums[i] else: cur_sum = nums[i] res = max(res,cur_sum) return res class Solution: def maxSubArray(self, nums: List[int]) -> int: # 动态规划dp[i],前i个数组的最大值和, dp[i]必须包含nums[i] dp = [0 for _ in range(len(nums))] dp[0] = nums[0] # 状态转移方程 dp[i] = dp[i-1] + nums[i] ;if dp[i-1] >= 0 # dp[i] = nums[i] ;if dp[i-1] < 0 for i in range(1,len(nums)): if dp[i-1] < 0: dp[i] = nums[i] else: dp[i] = dp[i-1] + nums[i] return max(dp) #优化 class Solution: def maxSubArray(self, nums: List[int]) -> int: for i in range(1, len(nums)): nums[i] += max(nums[i - 1], 0) return max(nums)