目录
100. 相同的树
101. 对称二叉树
102. 二叉树的层次遍历
103. 二叉树的锯齿形层次遍历
104. 二叉树的最大深度
105. 从前序与中序遍历序列构造二叉树
106. 从中序与后序遍历序列构造二叉树
107. 二叉树的层次遍历 II
108. 将有序数组转换为二叉搜索树
109. 有序链表转换二叉搜索树
110. 平衡二叉树
111. 二叉树的最小深度
112. 路径总和
113. 路径总和 II
114. 二叉树展开为链表
115. 不同的子序列
116. 填充每个节点的下一个右侧节点指针
117. 填充每个节点的下一个右侧节点指针 II
118. 杨辉三角
119. 杨辉三角 II
120. 三角形最小路径和
121. 买卖股票的最佳时机
122. 买卖股票的最佳时机 II
123. 买卖股票的最佳时机 III
124. 二叉树中的最大路径和
125. 验证回文串
126. 单词接龙 II
127. 单词接龙
128. 最长连续序列
129. 求根到叶子节点数字之和
130. 被围绕的区域
131. 分割回文串
132. 分割回文串 II
133. 克隆图
134. 加油站
135. 分发糖果
136. 只出现一次的数字
137. 只出现一次的数字 II
138. 复制带随机指针的链表
139. 单词拆分
140. 单词拆分 II
141. 环形链表
142. 环形链表 II
143. 重排链表
144. 二叉树的前序遍历
145. 二叉树的后序遍历
146. LRU 缓存机制
147. 对链表进行插入排序
148. 排序链表
149. 直线上最多的点数
150. 逆波兰表达式求值
151. 翻转字符串里的单词
152. 乘积最大子序列
153. 寻找旋转排序数组中的最小值
154. 寻找旋转排序数组中的最小值 II
155. 最小栈
160. 相交链表
162. 寻找峰值
164. 最大间距
165. 比较版本号
166. 分数到小数
167. 两数之和 II - 输入有序数组
168. Excel 表列名称
169. 多数元素
171. Excel 表列序号
172. 阶乘后的零
173. 二叉搜索树迭代器
174. 地下城游戏
179. 最大数
187. 重复的 DNA 序列
188. 买卖股票的最佳时机 IV
189. 旋转数组
190. 颠倒二进制位
191. 位 1 的个数
198. 打家劫舍
199. 二叉树的右视图
100. 相同的树
题目描述
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入: 1 1 / \ / \ 2 3 2 3 [1,2,3], [1,2,3] 输出: true
示例 2:
输入: 1 1 / \ 2 2 [1,2], [1,null,2] 输出: false
示例 3:
输入: 1 1 / \ / \ 2 1 1 2 [1,2,1], [1,1,2] 输出: false
解法
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
if p == q:
return True
if p is None or q is None or p.val != q.val:
return False
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == q) return true;
if (p == null || q == null || p.val != q.val) return false;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
C++
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == q) return true;
if (!p || !q || p->val != q->val) return false;
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
};
Go
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func isSameTree(p *TreeNode, q *TreeNode) bool {
if p == q {
return true
}
if p == nil || q == nil || p.Val != q.Val {
return false
}
return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}
…
101. 对称二叉树
题目描述
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3]
是对称的。
1 / \ 2 2 / \ / \ 3 4 4 3
但是下面这个 [1,2,2,null,3,null,3]
则不是镜像对称的:
1 / \ 2 2 \ \ 3 3
说明:
如果你可以运用递归和迭代两种方法解决这个问题,会很加分。
解法
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if root is None:
return True
return self.is_symmetric(root.left, root.right)
def is_symmetric(self, left: TreeNode, right: TreeNode) -> bool:
if left is None and right is None:
return True
if left is None or right is None or left.val != right.val:
return False
return self.is_symmetric(left.left, right.right) and self.is_symmetric(left.right, right.left)
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return isSymmetric(root.left, root.right);
}
private boolean isSymmetric(TreeNode left, TreeNode right) {
if (left == null && right == null) return true;
if (left == null || right == null || left.val != right.val) return false;
return isSymmetric(left.left, right.right) && isSymmetric(left.right, right.left);
}
}
C++
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (!root) return true;
return isSymmetric(root->left, root->right);
}
private:
bool isSymmetric(TreeNode* left, TreeNode* right) {
if (!left && !right) return true;
if (!left && right || left && !right || left->val != right->val) return false;
return isSymmetric(left->left, right->right) && isSymmetric(left->right, right->left);
}
};
…
102. 二叉树的层次遍历
题目描述
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回其层次遍历结果:
[ [3], [9,20], [15,7] ]
解法
队列实现。
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if root is None:
return []
res = []
q = []
q.append(root)
while q:
size = len(q)
t = []
for _ in range(size):
node = q.pop(0)
if node.left is not None:
q.append(node.left)
if node.right is not None:
q.append(node.right)
t.append(node.val)
res.append(t)
return res
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return Collections.emptyList();
Deque<TreeNode> q = new ArrayDeque<>();
q.offer(root);
List<List<Integer>> res = new ArrayList<>();
while (!q.isEmpty()) {
int size = q.size();
List<Integer> t = new ArrayList<>();
while (size-- > 0) {
TreeNode node = q.poll();
t.add(node.val);
if (node.left != null) q.offer(node.left);
if (node.right != null) q.offer(node.right);
}
res.add(t);
}
return res;
}
}
C++
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if (!root) return {};
vector<vector<int>> res;
queue<TreeNode*> q{{root}};
while (!q.empty()) {
vector<int> oneLevel;
for (int i = q.size(); i > 0; --i) {
TreeNode* t = q.front();
q.pop();
oneLevel.push_back(t->val);
if (t->left) q.push(t->left);
if (t->right) q.push(t->right);
}
res.push_back(oneLevel);
}
return res;
}
};
…
103. 二叉树的锯齿形层次遍历
题目描述
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回锯齿形层次遍历如下:
[ [3], [20,9], [15,7] ]
解法
Python3
Java
class Solution {
private List<List<Integer>> list;
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
list = new ArrayList<>();
lever(root, 0);
for (int i = 1; i < list.size(); i = i + 2) {
List<Integer> nList = list.get(i);
List<Integer> nnl = new ArrayList<>();
for (int j = nList.size() - 1; j >= 0; j--) nnl.add(nList.get(j));
list.set(i, nnl);
}
return list;
}
private void lever(TreeNode root, int l) {
if (root == null) return;
while (l > list.size() - 1) list.add(new ArrayList<>());
list.get(l++).add(root.val);
lever(root.left, l);
lever(root.right, l);
}
}
…
104. 二叉树的最大深度
题目描述
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回它的最大深度 3 。
解法
递归遍历左右子树,求左右子树的最大深度 +1 即可。
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if root is None:
return 0
l = self.maxDepth(root.left)
r = self.maxDepth(root.right)
return 1 + max(l, r)
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) return 0;
int l = maxDepth(root.left);
int r = maxDepth(root.right);
return 1 + Math.max(l, r);
}
}
C++
class Solution {
public:
int maxDepth(TreeNode* root) {
if (!root) return 0;
int l = maxDepth(root->left);
int r = maxDepth(root->right);
return max(l, r) + 1;
}
};
…
105. 从前序与中序遍历序列构造二叉树
题目描述
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3 / \ 9 20 / \ 15 7
解法
先遍历前序节点,对于前序的根节点,在中序节点 [i1, i2]
中找到根节点的位置 pos,就可以将中序节点分成:左子树 [i1, pos - 1]
、右子树 [pos + 1, i2]
。
通过左右子树的区间,可以计算出左、右子树节点的个数,假设为 m、n。然后在前序节点中,从根节点往后的 m 个节点为左子树,再往后的 n 个节点为右子树。
递归求解即可。
前序遍历:先遍历根节点,再遍历左右子树;中序遍历:先遍历左子树,再遍历根节点,最后遍历右子树。
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
indexes = {}
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
def build(preorder, inorder, p1, p2, i1, i2) -> TreeNode:
if p1 > p2 or i1 > i2:
return None
root_val = preorder[p1]
pos = self.indexes[root_val]
root = TreeNode(root_val)
# pos==i1,说明只有右子树,左子树为空
root.left = None if pos == i1 else build(preorder, inorder, p1 + 1, p1 - i1 + pos, i1, pos - 1)
# pos==i2,说明只有左子树,右子树为空
root.right = None if pos == i2 else build(preorder, inorder, p1 - i1 + pos + 1, p2, pos + 1, i2)
return root
n = len(inorder)
for i in range(n):
self.indexes[inorder[i]] = i
return build(preorder, inorder, 0, n - 1, 0, n - 1)
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private Map<Integer, Integer> indexes = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = inorder.length;
for (int i = 0; i < n; ++i) {
indexes.put(inorder[i], i);
}
return build(preorder, inorder, 0, n - 1, 0, n - 1);
}
private TreeNode build(int[] preorder, int[] inorder, int p1, int p2, int i1, int i2) {
if (p1 > p2 || i1 > i2) return null;
int rootVal = preorder[p1];
int pos = indexes.get(rootVal);
TreeNode node = new TreeNode(rootVal);
// pos==i1,说明只有右子树,左子树为空
node.left = pos == i1 ? null : build(preorder, inorder, p1 + 1, pos - i1 + p1, i1, pos - 1);
// pos==i2,说明只有左子树,右子树为空
node.right = pos == i2 ? null : build(preorder, inorder, pos - i1 + p1 + 1, p2, pos + 1, i2);
return node;
}
}
…
106. 从中序与后序遍历序列构造二叉树
题目描述
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3 / \ 9 20 / \ 15 7
解法
思路同 105。
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
indexes = {}
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
def build(inorder, postorder, i1, i2, p1, p2):
if i1 > i2 or p1 > p2:
return None
root_val = postorder[p2]
pos = self.indexes[root_val]
root = TreeNode(root_val)
root.left = None if pos == i1 else build(inorder, postorder, i1, pos - 1, p1, p1 - i1 + pos - 1)
root.right = None if pos == i2 else build(inorder, postorder, pos + 1, i2, p1 - i1 + pos, p2 - 1)
return root
n = len(inorder)
for i in range(n):
self.indexes[inorder[i]] = i
return build(inorder, postorder, 0, n - 1, 0, n - 1)
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private Map<Integer, Integer> indexes = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
int n = inorder.length;
for (int i = 0; i < n; ++i) {
indexes.put(inorder[i], i);
}
return build(inorder, postorder, 0, inorder.length - 1, 0, postorder.length - 1);
}
private TreeNode build(int[] inorder, int[] postorder, int i1, int i2, int p1, int p2) {
if (i1 > i2 || p1 > p2) return null;
int rootVal = postorder[p2];
int pos = indexes.get(rootVal);
TreeNode root = new TreeNode(rootVal);
root.left = pos == i1 ? null : build(inorder, postorder, i1, pos - 1, p1, p1 - i1 + pos - 1);
root.right = pos == i2 ? null : build(inorder, postorder, pos + 1, i2, p1 - i1 + pos, p2 - 1);
return root;
}
}
C++
class Solution {
public:
TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
return buildTree(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
}
TreeNode *buildTree(vector<int> &inorder, int iLeft, int iRight, vector<int> &postorder, int pLeft, int pRight) {
if (iLeft > iRight || pLeft > pRight) return NULL;
TreeNode *cur = new TreeNode(postorder[pRight]);
int i = 0;
for (i = iLeft; i < inorder.size(); ++i) {
if (inorder[i] == cur->val)
break;
}
cur->left = buildTree(inorder, iLeft, i - 1, postorder, pLeft, pLeft + i - iLeft - 1);
cur->right = buildTree(inorder, i + 1, iRight, postorder, pLeft + i - iLeft, pRight - 1);
return cur;
}
};
…
107. 二叉树的层次遍历 II
题目描述
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:
给定二叉树 [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回其自底向上的层次遍历为:
[ [15,7], [9,20], [3] ]
解法
同 102,最后反转一下结果即可。
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
if root is None:
return []
q = [root]
res = []
while q:
size = len(q)
t = []
for _ in range(size):
node = q.pop(0)
t.append(node.val)
if node.left is not None:
q.append(node.left)
if node.right is not None:
q.append(node.right)
res.append(t)
return res[::-1]
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
if (root == null) return Collections.emptyList();
Deque<TreeNode> q = new ArrayDeque<>();
List<List<Integer>> res = new ArrayList<>();
q.offer(root);
while (!q.isEmpty()) {
int size = q.size();
List<Integer> t = new ArrayList<>();
while (size-- > 0) {
TreeNode node = q.poll();
t.add(node.val);
if (node.left != null) q.offer(node.left);
if (node.right != null) q.offer(node.right);
}
res.add(0, t);
}
return res;
}
}
…
108. 将有序数组转换为二叉搜索树
题目描述
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9], 一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树: 0 / \ -3 9 / / -10 5
解法
Python3
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return sortedArrayToBST(nums, 0, nums.length - 1);
}
private TreeNode sortedArrayToBST(int[] nums, int l, int r) {
if (l > r) {
return null;
}
int mid = (l + r) >> 1;
TreeNode root = new TreeNode(nums[mid]);
root.left = sortedArrayToBST(nums, l, mid - 1);
root.right = sortedArrayToBST(nums, mid + 1, r);
return root;
}
}
…
109. 有序链表转换二叉搜索树
题目描述
给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定的有序链表: [-10, -3, 0, 5, 9], 一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树: 0 / \ -3 9 / / -10 5
解法
Python3
Java
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if(head==null) return null;
if(head.next==null) return new TreeNode(head.val);
ListNode slow = head;
ListNode fast = head;
ListNode prev = null;
while(fast!=null && fast.next!=null){
prev = slow;
slow=slow.next;
fast=fast.next.next;
}
TreeNode root = new TreeNode(Objects.requireNonNull(prev).next.val);
prev.next = null;
root.left = sortedListToBST(head);
root.right = sortedListToBST(slow.next);
return root;
}
}
…
110. 平衡二叉树
题目描述
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3 / \ 9 20 / \ 15 7
返回 true
。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1 / \ 2 2 / \ 3 3 / \ 4 4
返回 false
。
解法
Python3
Java
class Solution {
public boolean isBalanced(TreeNode root) {
return depth(root) != -1;
}
private int depth(TreeNode root) {
if (root == null) return 0;
int left = depth(root.left);
if (left == -1) return -1;
int right = depth(root.right);
if (right == -1 || Math.abs(left - right) > 1) return -1;
return Math.max(left, right) + 1;
}
}
…
111. 二叉树的最小深度
题目描述
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回它的最小深度 2.
解法
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def minDepth(self, root: TreeNode) -> int:
if root is None:
return 0
if root.left is None and root.right is None:
return 1
l = self.minDepth(root.left)
r = self.minDepth(root.right)
# 如果左子树和右子树其中一个为空,那么需要返回比较大的那个子树的深度
if root.left is None or root.right is None:
return l + r + 1
# 左右子树都不为空,返回最小深度+1即可
return min(l, r) + 1
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int minDepth(TreeNode root) {
if (root == null) return 0;
if (root.left == null && root.right == null) return 1;
int l = minDepth(root.left);
int r = minDepth(root.right);
if (root.left == null || root.right == null) return l + r + 1;
return Math.min(l, r) + 1;
}
}
…
112. 路径总和
题目描述
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5 / \ 4 8 / / \ 11 13 4 / \ \ 7 2 1
返回 true
, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2
。
解法
递归求解,递归地询问它的子节点是否能满足条件即可。
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
def dfs(root, sum):
if root is None:
return False
if root.val == sum and root.left is None and root.right is None:
return True
return dfs(root.left, sum - root.val) or dfs(root.right, sum - root.val)
return dfs(root, sum)
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
return dfs(root, sum);
}
private boolean dfs(TreeNode root, int sum) {
if (root == null) return false;
if (root.val == sum && root.left == null && root.right == null) return true;
return dfs(root.left, sum - root.val) || dfs(root.right, sum - root.val);
}
}
…
113. 路径总和 II
题目描述
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5 / \ 4 8 / / \ 11 13 4 / \ / \ 7 2 5 1
返回:
[ [5,4,11,2], [5,8,4,5] ]
解法
深度优先搜索+路径记录。
Python3
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
def dfs(root, sum):
if root is None:
return
path.append(root.val)
if root.val == sum and root.left is None and root.right is None:
res.append(path.copy())
dfs(root.left, sum - root.val)
dfs(root.right, sum - root.val)
path.pop()
if not root:
return []
res = []
path = []
dfs(root, sum)
return res
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private List<List<Integer>> res;
private List<Integer> path;
public List<List<Integer>> pathSum(TreeNode root, int sum) {
if (root == null) return Collections.emptyList();
res = new ArrayList<>();
path = new ArrayList<>();
dfs(root, sum);
return res;
}
private void dfs(TreeNode root, int sum) {
if (root == null) return;
path.add(root.val);
if (root.val == sum && root.left == null && root.right == null) {
res.add(new ArrayList<>(path));
}
dfs(root.left, sum - root.val);
dfs(root.right, sum - root.val);
path.remove(path.size() - 1);
}
}
…
114. 二叉树展开为链表
题目描述
给定一个二叉树,原地将它展开为链表。
例如,给定二叉树
1 / \ 2 5 / \ \ 3 4 6
将其展开为:
1 \ 2 \ 3 \ 4 \ 5 \ 6
解法
Python3
Java
class Solution {
public void flatten(TreeNode root) {
if (root==null) return;
TreeNode right = root.right;
flatten(right);
flatten(root.left);
root.right = root.left;
root.left = null;
TreeNode cache = root;
while (cache.right!=null) cache = cache.right;
cache.right = right;
}
}
…
115. 不同的子序列
题目描述
给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE"
是 "ABCDE"
的一个子序列,而 "AEC"
不是)
示例 1:
输入: S ="rabbbit"
, T ="rabbit" 输出: 3
解释: 如下图所示, 有 3 种可以从 S 中得到"rabbit" 的方案
。 (上箭头符号 ^ 表示选取的字母)rabbbit
^^^^ ^^rabbbit
^^ ^^^^rabbbit
^^^ ^^^
示例 2:
输入: S ="babgbag"
, T ="bag" 输出: 5
解释: 如下图所示, 有 5 种可以从 S 中得到"bag" 的方案
。 (上箭头符号 ^ 表示选取的字母)babgbag
^^ ^babgbag
^^ ^babgbag
^ ^^babgbag
^ ^^babgbag
^^^
解法
Python3
Java
class Solution {
public int numDistinct(String s, String t) {
int[][] hash = new int[256][t.length() + 1];
int[] cnt = new int[t.length() + 1];
cnt[0] = 1;
for (int i = 0; i < t.length();) {
char c = t.charAt(i);
hash[c][++hash[c][0]] = ++i;
}
for(char c : s.toCharArray()) {
for(int i = hash[c][0]; i > 0; i--) {
cnt[hash[c][i]] += cnt[hash[c][i] - 1];
}
}
return cnt[t.length()];
}
}
…
116. 填充每个节点的下一个右侧节点指针
题目描述
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node { int val; Node *left; Node *right; Node *next; }
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL
。
初始状态下,所有 next 指针都被设置为 NULL
。
示例:
输入:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":null,"right":null,"val":4},"next":null,"right":{"$id":"4","left":null,"next":null,"right":null,"val":5},"val":2},"next":null,"right":{"$id":"5","left":{"$id":"6","left":null,"next":null,"right":null,"val":6},"next":null,"right":{"$id":"7","left":null,"next":null,"right":null,"val":7},"val":3},"val":1} 输出:{"$id":"1","left":{"$id":"2","left":{"$id":"3","left":null,"next":{"$id":"4","left":null,"next":{"$id":"5","left":null,"next":{"$id":"6","left":null,"next":null,"right":null,"val":7},"right":null,"val":6},"right":null,"val":5},"right":null,"val":4},"next":{"$id":"7","left":{"$ref":"5"},"next":null,"right":{"$ref":"6"},"val":3},"right":{"$ref":"4"},"val":2},"next":null,"right":{"$ref":"7"},"val":1} 解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
提示:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
解法
Python3
Java
class Solution {
public void connect(TreeLinkNode root) {
if (root == null || root.left == null) return;
root.left.next = root.right;
if (root.next == null) root.right.next = null;
else root.right.next = root.next.left;
connect(root.left);
connect(root.right);
}
}
…
117. 填充每个节点的下一个右侧节点指针 II
题目描述
给定一个二叉树
struct Node { int val; Node *left; Node *right; Node *next; }
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL
。
初始状态下,所有 next 指针都被设置为 NULL
。
进阶:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
示例:
输入:root = [1,2,3,4,5,null,7] 输出:[1,#,2,3,#,4,5,7,#] 解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。
提示:
- 树中的节点数小于
6000
-100 <= node.val <= 100
解法
Python3
Java
public class Solution {
public void connect(TreeLinkNode root) {
if (root == null) return;
TreeLinkNode first_node_next_layer = null;
TreeLinkNode preNode = null;
for (TreeLinkNode curNode = root; curNode != null; curNode = curNode.next) {
if (curNode.left != null) {
if (preNode == null) {
preNode = curNode.left;
first_node_next_layer = curNode.left;
} else {
preNode.next = curNode.left;
preNode = preNode.next;
}
}
if (curNode.right != null) {
if (preNode == null) {
preNode = curNode.right;
first_node_next_layer = curNode.right;
} else {
preNode.next = curNode.right;
preNode = preNode.next;
}
}
}
connect(first_node_next_layer);
}
}
…
118. 杨辉三角
题目描述
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 5 输出: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ]
解法
先设置每一行首尾元素为 1,其它元素为 0。然后根据杨辉三角,设置每一行其它元素即可。
Python3
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
if numRows == 0:
return []
res = []
for i in range(numRows):
t = [1 if j == 0 or j == i else 0 for j in range(i + 1)]
for j in range(1, i):
t[j] = res[i - 1][j - 1] + res[i - 1][j]
res.append(t)
return res
Java
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> res = new ArrayList<>();
if (numRows == 0) return res;
for (int i = 0; i < numRows; ++i) {
// 每一行
List<Integer> t = new ArrayList<>();
for (int j = 0; j < i + 1; ++j) {
boolean firstOrLast = j == 0 || j == i;
// 设置每一行首尾元素为1,其它元素为0
t.add(firstOrLast ? 1 : 0);
}
for (int j = 1; j < i; ++j) {
int val = res.get(i - 1).get(j - 1) + res.get(i - 1).get(j);
t.set(j, val);
}
res.add(t);
}
return res;
}
}
…
119. 杨辉三角 II
题目描述
给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 3 输出: [1,3,3,1]
进阶:
你可以优化你的算法到 O(k) 空间复杂度吗?
解法
Python3
Java
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> ret = new LinkedList<>();
long nk = 1;
for (int i = 0; i <= rowIndex; i++) {
ret.add((int) nk);
nk = nk * (rowIndex - i) / (i + 1);
}
return ret;
}
}
…
120. 三角形最小路径和
题目描述
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[ [2], [3,4], [6,5,7], [4,1,8,3] ]
自顶向下的最小路径和为 11
(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。
解法
Python3
Java
class Solution {
private int[][] cache = null;
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
cache = new int[n][triangle.get(n - 1).size()];
for (int[] row : cache) Arrays.fill(row, -1);
return dfs(triangle,0,0);
}
private int dfs(List<List<Integer>> triangle, int row, int col) {
if (row == triangle.size()) return 0;
if (cache[row][col] != -1) return cache[row][col];
int l = dfs(triangle,row+1,col);
int r = dfs(triangle,row+1,col+1);
int res = Math.min(l,r)+triangle.get(row).get(col);
cache[row][col] = res;
return res;
}
}
…
121. 买卖股票的最佳时机
题目描述
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
解法
Python3
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
res = 0
min_price = prices[0]
for price in prices:
min_price = min(min_price, price)
res = max(res, price - min_price)
return res
Java
class Solution {
public int maxProfit(int[] prices) {
if (prices == null) return 0;
int res = 0;
int min = Integer.MAX_VALUE;
for (int price : prices) {
min = Math.min(min, price);
res = Math.max(res, price - min);
}
return res;
}
}
…
122. 买卖股票的最佳时机 II
题目描述
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4] 输出: 7 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5] 输出: 4 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
解法
所有上涨交易日都做买卖,所有下跌交易日都不做买卖,这样便能实现利润最大化。
Python3
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
res = 0
for i in range(1, len(prices)):
t = prices[i] - prices[i - 1]
res += max(t, 0)
return res
Java
class Solution {
public int maxProfit(int[] prices) {
if (prices == null) return 0;
int res = 0;
for (int i = 1, n = prices.length; i < n; ++i) {
// 策略是所有上涨交易日都做买卖,所以下跌交易日都不做买卖
int t = prices[i] - prices[i - 1];
res += Math.max(t, 0);
}
return res;
}
}
C++
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0, n;
if ((n = prices.size()) == 0) return 0;
for (int i = 1; i < n; ++i)
{
int t = prices[i] - prices[i - 1];
res += max(0, t);
}
return res;
}
};
…
123. 买卖股票的最佳时机 III
题目描述
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [3,3,5,0,0,3,1,4] 输出: 6 解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:
输入: [1,2,3,4,5] 输出: 4 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1] 输出: 0 解释: 在这个情况下, 没有交易完成, 所以最大利润为 0。
解法
Python3
Java
class Solution {
public int maxProfit(int[] prices) {
if (prices.length <= 1) return 0;
int m = 2 , n = prices.length;
int[][] dp = new int[m+1][n];
for (int i = 1; i <= m; i++) {
int maxdiff = Integer.MIN_VALUE;
for (int j = 1; j < n; j++) {
maxdiff = Math.max(maxdiff, dp[i-1][j-1] - prices[j-1]);
dp[i][j] = Math.max(dp[i][j-1], prices[j] + maxdiff);
}
}
return dp[m][n-1];
}
}
…
124. 二叉树中的最大路径和
题目描述
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
示例 1:
输入: [1,2,3] 1 / \ 2 3 输出: 6
示例 2:
输入: [-10,9,20,null,null,15,7] -10 / \ 9 20 / \ 15 7 输出: 42
解法
Python3
Java
class Solution {
private int val = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
dfs(root);
return val;
}
public int dfs(TreeNode root) {
if (root == null) {
return 0;
}
int left = Math.max(0, dfs(root.left));
int right = Math.max(0, dfs(root.right));
int val1 = root.val + left + right;
int val2 = root.val + Math.max(0, Math.max(left, right));
val = Math.max(val, val1);
return val2;
}
}
…
125. 验证回文串
题目描述
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama" 输出: true
示例 2:
输入: "race a car" 输出: false
解法
Python3
Java
class Solution {
public boolean isPalindrome(String s) {
int i = 0;
int j = s.length() - 1;
while (i < j) {
while (i < j && !Character.isLetterOrDigit(s.charAt(i))) {
i++;
}
while (i < j && !Character.isLetterOrDigit(s.charAt(j))) {
j--;
}
if (i < j && Character.toUpperCase(s.charAt(i)) != Character.toUpperCase(s.charAt(j))) {
return false;
}
i++;
j--;
}
return true;
}
}
…
126. 单词接龙 II
题目描述
给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
- 每次转换只能改变一个字母。
- 转换过程中的中间单词必须是字典中的单词。
说明:
- 如果不存在这样的转换序列,返回一个空列表。
- 所有单词具有相同的长度。
- 所有单词只由小写字母组成。
- 字典中不存在重复的单词。
- 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] 输出: [ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ]
示例 2:
输入: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log"] 输出: [] 解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。
解法
Python3
Java
class Solution {
private boolean isConnected = false;
private Map<String, List<String>> hs;
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
hs = new HashMap<>(16);
List<List<String>> result = new ArrayList<>();
if(!wordList.contains(endWord))
return result;
HashSet<String> dict = new HashSet<>(wordList);
Set<String> fwd = new HashSet<>();
fwd.add(beginWord);
Set<String> bwd = new HashSet<>();
bwd.add(endWord);
bfs(fwd, bwd, dict, false);
if(!isConnected) return result;
List<String> temp = new ArrayList<>();
temp.add(beginWord);
dfs(result, temp, beginWord, endWord);
return result;
}
private void bfs(Set<String> forward, Set<String> backward, Set<String> dict, boolean swap){
if(forward.isEmpty() || backward.isEmpty()) return;
if(forward.size() > backward.size()){
bfs(backward, forward, dict, !swap);
return;
}
dict.removeAll(forward);
dict.removeAll(backward);
Set<String> set3 = new HashSet<>();
for(String str : forward)
for (int i = 0; i < str.length(); i++) {
char[] ary = str.toCharArray();
for (char j = 'a'; j <= 'z'; j++) {
ary[i] = j;
String temp = new String(ary);
if (!backward.contains(temp) && !dict.contains(temp)) continue;
String key = !swap ? str : temp;
String val = !swap ? temp : str;
if (!hs.containsKey(key)) hs.put(key, new ArrayList<>());
if (backward.contains(temp)) {
hs.get(key).add(val);
isConnected = true;
}
if (!isConnected && dict.contains(temp)) {
hs.get(key).add(val);
set3.add(temp);
}
}
}
if(!isConnected) bfs(set3, backward, dict, swap);
}
private void dfs(List<List<String>> result, List<String> temp, String start, String end){
if(start.equals(end)){
result.add(new ArrayList<>(temp));
return;
}
if(!hs.containsKey(start)) return;
for(String s : hs.get(start)){
temp.add(s);
dfs(result, temp, s, end);
temp.remove(temp.size()-1);
}
}
}
…
127. 单词接龙
题目描述
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
- 每次转换只能改变一个字母。
- 转换过程中的中间单词必须是字典中的单词。
说明:
- 如果不存在这样的转换序列,返回 0。
- 所有单词具有相同的长度。
- 所有单词只由小写字母组成。
- 字典中不存在重复的单词。
- 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] 输出: 5 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
示例 2:
输入: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log"] 输出: 0 解释: endWord "cog" 不在字典中,所以无法进行转换。
解法
Python3
Java
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Queue<String> queue = new LinkedList<>();
// 需要转hashSet
Set<String> wordSet = new HashSet<>(wordList);
queue.offer(beginWord);
int level = 1;
int curNum = 1;
int nextNum = 0;
while (!queue.isEmpty()) {
String s = queue.poll();
--curNum;
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; ++i) {
char ch = chars[i];
for (char j = 'a'; j <= 'z'; ++j) {
chars[i] = j;
String tmp = new String(chars);
// 字典中包含生成的中间字符串
if (wordSet.contains(tmp)) {
// 中间字符串与 endWord 相等
if (endWord.equals(tmp)) {
return level + 1;
}
// 中间字符串不是 endWord,则入队
queue.offer(tmp);
++nextNum;
// 确保之后不会再保存 tmp 字符串
wordSet.remove(tmp);
}
}
chars[i] = ch;
}
if (curNum == 0) {
curNum = nextNum;
nextNum = 0;
++level;
}
}
return 0;
}
}
…
128. 最长连续序列
题目描述
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
解法
Python3
Java
class Solution {
public int longestConsecutive(int[] nums) {
if (nums.length == 0) return 0;
Arrays.sort(nums);
int start = 0, casch = nums[0], longest = 0;
for (int i = 1; i < nums.length; i++) {
int nc = nums[i] , con = nc - casch;
if (con == 0) {
start++;
} else if (con != 1) {
longest = Math.max(i - start, longest);
start = i;
}
casch = nc;
}
return Math.max(nums.length - start, longest);
}
}
…
129. 求根到叶子节点数字之和
题目描述
给定一个二叉树,它的每个结点都存放一个 0-9
的数字,每条从根到叶子节点的路径都代表一个数字。
例如,从根到叶子节点路径 1->2->3
代表数字 123
。
计算从根到叶子节点生成的所有数字之和。
说明: 叶子节点是指没有子节点的节点。
示例 1:
输入: [1,2,3] 1 / \ 2 3 输出: 25 解释: 从根到叶子节点路径1->2
代表数字12
. 从根到叶子节点路径1->3
代表数字13
. 因此,数字总和 = 12 + 13 =25
.
示例 2:
输入: [4,9,0,5,1] 4 / \ 9 0 / \ 5 1 输出: 1026 解释: 从根到叶子节点路径4->9->5
代表数字 495. 从根到叶子节点路径4->9->1
代表数字 491. 从根到叶子节点路径4->0
代表数字 40. 因此,数字总和 = 495 + 491 + 40 =1026
.
解法
Python3
Java
class Solution {
public int sumNumbers(TreeNode root) {
return sumNumbers(root,0);
}
private int sumNumbers(TreeNode root, int sum) {
if (root==null) return 0;
sum = sum *10 + root.val;
if (root.left==null && root.right==null) return sum;
return sumNumbers(root.left,sum)+sumNumbers(root.right,sum);
}
}
…
130. 被围绕的区域
题目描述
给定一个二维的矩阵,包含 'X'
和 'O'
(字母 O)。
找到所有被 'X'
围绕的区域,并将这些区域里所有的 'O'
用 'X'
填充。
示例:
X X X X X O O X X X O X X O X X
运行你的函数后,矩阵变为:
X X X X X X X X X X X X X O X X
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O'
都不会被填充为 'X'
。 任何不在边界上,或不与边界上的 'O'
相连的 'O'
最终都会被填充为 'X'
。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
解法
Python3
Java
class Solution {
/**
* 坐标点
*/
private class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public void solve(char[][] board) {
if (board == null || board.length < 3 || board[0].length < 3) {
return;
}
int m = board.length;
int n = board[0].length;
// top & bottom
for (int i = 0; i < n; ++i) {
bfs(board, 0, i);
bfs(board, m - 1, i);
}
// left & right
for (int i = 1; i < m - 1; ++i) {
bfs(board, i, 0);
bfs(board, i, n - 1);
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (board[i][j] == 'O') {
board[i][j] = 'X';
} else if (board[i][j] == 'Y') {
board[i][j] = 'O';
}
}
}
}
/**
* 广度优先搜索
* @param board
* @param i
* @param j
*/
private void bfs(char[][] board, int i, int j) {
Queue<Point> queue = new LinkedList<>();
if (isValid(board, i, j)) {
// 遇到'O',修改为'Y'
board[i][j] = 'Y';
queue.offer(new Point(i, j));
}
while (!queue.isEmpty()) {
Point p = queue.poll();
// 获取下一层所有有效坐标点,并加入队列
List<Point> points = getNextLevelValidPoints(board, p.x, p.y);
for (Point point : points) {
queue.offer(point);
}
}
}
/**
* 获取下一层所有有效坐标点,将这些坐标点修改为 'Y' 并返回
* @param board
* @param i
* @param j
* @return list
*/
private List<Point> getNextLevelValidPoints(char[][] board, int i, int j) {
List<Point> points = new ArrayList<>();
Point[] arr = new Point[] { new Point(i - 1, j), new Point(i + 1, j), new Point(i, j - 1),
new Point(i, j + 1) };
for (Point point : arr) {
if (isValid(board, point.x, point.y)) {
board[point.x][point.y] = 'Y';
points.add(point);
}
}
return points;
}
/**
* 判断坐标是否有效
* @param board
* @param i
* @param j
* @return boolean
*/
private boolean isValid(char[][] board, int i, int j) {
int m = board.length;
int n = board[0].length;
// 当前坐标对应的值是'O',才算有效
return i >= 0 && i <= m - 1 && j >= 0 && j <= n - 1 && board[i][j] == 'O';
}
}
…
131. 分割回文串
题目描述
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ]
解法
Python3
Java
class Solution {
private List<List<String>> res;
public List<List<String>> partition(String s) {
res= new ArrayList<>();
func(new ArrayList<>(),0,s);
return res;
}
private void func(List<String> temp, int start, String str){
if(start>=str.length()){
res.add(new ArrayList<>(temp));
return;
}
int ed=str.indexOf(str.charAt(start),start+1);
while(ed>0){
int s=start;
int e=ed;
boolean flag=false;
while(s<e){
if(str.charAt(s)==str.charAt(e)){
s++;
e--;
} else{
flag=true;
break;
}
}
if(!flag){
temp.add(str.substring(start,ed+1));
func(temp,ed+1,str);
temp.remove(temp.size()-1);
}
ed=str.indexOf(str.charAt(start),ed+1);
}
temp.add(str.substring(start,start+1));
func(temp,start+1,str);
temp.remove(temp.size()-1);
}
}
…
132. 分割回文串 II
题目描述
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。
示例:
输入: "aab" 输出: 1 解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
解法
Python3
Java
class Solution {
public int minCut(String s) {
if(s==null || s.length()<=1)return 0;
int len = s.length();
int[] dp = new int[len];
for(int i=0;i<len;i++) dp[i] = len - 1;
for(int i=0;i<len;i++){
mincutHelper(s , i , i , dp);
mincutHelper(s, i , i+1 , dp);
}
return dp[len-1];
}
private void mincutHelper(String s, int i, int j, int[] dp){
int len = s.length();
while(i>=0 && j<len && s.charAt(i)==s.charAt(j)){
dp[j] = Math.min(dp[j] , (i==0?-1:dp[i-1])+1);
i--;
j++;
}
}
}
…
133. 克隆图
题目描述
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val
(int
) 和其邻居的列表(list[Node]
)。
class Node { public int val; public List<Node> neighbors; }
测试用例格式:
简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1,第二个节点值为 2,以此类推。该图在测试用例中使用邻接列表表示。
邻接列表是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。
示例 1:
输入:adjList = [[2,4],[1,3],[2,4],[1,3]] 输出:[[2,4],[1,3],[2,4],[1,3]] 解释: 图中有 4 个节点。 节点 1 的值是 1,它有两个邻居:节点 2 和 4 。 节点 2 的值是 2,它有两个邻居:节点 1 和 3 。 节点 3 的值是 3,它有两个邻居:节点 2 和 4 。 节点 4 的值是 4,它有两个邻居:节点 1 和 3 。
示例 2:
输入:adjList = [[]] 输出:[[]] 解释:输入包含一个空列表。该图仅仅只有一个值为 1 的节点,它没有任何邻居。
示例 3:
输入:adjList = [] 输出:[] 解释:这个图是空的,它不含任何节点。
示例 4:
输入:adjList = [[2],[1]] 输出:[[2],[1]]
提示:
- 节点数介于 1 到 100 之间。
- 每个节点值都是唯一的。
- 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
- 由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
- 图是连通图,你可以从给定节点访问到所有节点。
解法
Python3
Java
class Solution {
private Map<Node, Node> cache;
public Node cloneGraph(Node node) {
cache = new HashMap<>(16);
return helper(node);
}
private Node helper(Node node) {
if (node == null) return null;
else if (cache.containsKey(node)) return cache.get(node);
Node nodeCopy = new Node(node.val,new ArrayList<>());
cache.put(node, nodeCopy);
for (Node neighbor : node.neighbors) nodeCopy.neighbors.add(helper(neighbor));
return nodeCopy;
}
}
…
134. 加油站
题目描述
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i]
升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i]
升。你从其中的一个加油站出发,开始时油箱为空。
如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。
说明:
- 如果题目有解,该答案即为唯一答案。
- 输入数组均为非空数组,且长度相同。
- 输入数组中的元素均为非负数。
示例 1:
输入: gas = [1,2,3,4,5] cost = [3,4,5,1,2] 输出: 3 解释: 从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油 开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油 开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油 开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油 开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油 开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。 因此,3 可为起始索引。
示例 2:
输入: gas = [2,3,4] cost = [3,4,3] 输出: -1 解释: 你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。 我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油 开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油 开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油 你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。 因此,无论怎样,你都不可能绕环路行驶一周。
解法
Python3
Java
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
if(gas.length!=cost.length) return -1;
int sum=0,total=0,index=0;
for(int i=0;i<gas.length;i++){
int sy = gas[i] - cost[i];
sum+= sy;
total+= sy;
if(sum<0){
index=i+1;
sum=0;
}
}
if(total<0) return -1;
return index;
}
}
…
135. 分发糖果
题目描述
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
- 每个孩子至少分配到 1 个糖果。
- 相邻的孩子中,评分高的孩子必须获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
示例 1:
输入: [1,0,2] 输出: 5 解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
示例 2:
输入: [1,2,2] 输出: 4 解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。 第三个孩子只得到 1 颗糖果,这已满足上述两个条件。
解法
Python3
Java
class Solution {
public int candy(int[] ratings) {
if (ratings == null || ratings.length == 0) return 0;
else if (ratings.length == 1) return 1;
int base = 1 ,cur = base ,sum = cur ,smallNum = 0 ,lastBigCur = cur;
for (int i = 1; i < ratings.length; i++) {
if (ratings[i - 1] < ratings[i]) {
smallNum = 0;
cur += base;
lastBigCur = cur;
sum += cur;
} else if (ratings[i - 1] == ratings[i]) {
smallNum = 0;
cur = base;
lastBigCur = cur;
sum += base;
} else {
if (cur == base) {
smallNum++;
sum = sum + cur + smallNum;
if (lastBigCur - 1 == smallNum) {
lastBigCur += base;
sum += base;
}
} else {
cur = base;
sum += cur;
}
}
}
return sum;
}
}
…
136. 只出现一次的数字
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4
解法
异或运算求解。
首先明确,两个相同的数异或之后的结果为 0。对该数组所有元素进行异或运算,结果就是那个只出现一次的数字。
Python3
class Solution:
def singleNumber(self, nums: List[int]) -> int:
res = 0
for num in nums:
res ^= num
return res
Java
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for (int num : nums) {
res ^= num;
}
return res;
}
}
JavaScript
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function (nums) {
let res = 0;
for (let num of nums) {
res ^= num;
}
return res;
};
Go
func singleNumber(nums []int) int {
res := 0
for _, v := range nums {
res ^= v
}
return res
}
…
137. 只出现一次的数字 II
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2] 输出: 3
示例 2:
输入: [0,1,0,1,0,1,99] 输出: 99
解法
统计所有数字每个位中 1 出现的次数,对于某个位,1 出现的次数一定是 3 的倍数 +1 或 0。对这个数 %3 得到的结果就是那个出现一次的数字在该位上的值。
Python3
class Solution:
def singleNumber(self, nums: List[int]) -> int:
bits = [0] * 32
for num in nums:
for i in range(32):
bits[i] += (num & 1)
num >>= 1
res = 0
for i in range(32):
if bits[i] % 3 != 0:
res += (1 << i)
# 如果为负数,先将 0-32 位取反(即 res ^ 0xffffffff ),再将所有位取反(即 ~ )
return res if bits[31] % 3 == 0 else ~(res ^ 0xffffffff)
Java
class Solution {
public int singleNumber(int[] nums) {
int[] bits = new int[32];
for (int num : nums) {
for (int i = 0; i < 32; ++i) {
bits[i] += (num & 1);
num >>= 1;
}
}
int res = 0;
for (int i = 0; i < 32; ++i) {
if (bits[i] % 3 == 1) {
res += (1 << i);
}
}
return res;
}
}
…
138. 复制带随机指针的链表
题目描述
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n
个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index]
表示:
val
:一个表示Node.val
的整数。random_index
:随机指针指向的节点索引(范围从0
到n-1
);如果不指向任何节点,则为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。
提示:
-10000 <= Node.val <= 10000
Node.random
为空(null)或指向链表中的节点。- 节点数目不超过 1000 。
解法
Python3
Java
/**
* Definition for singly-linked list with a random pointer.
* class RandomListNode {
* int label;
* RandomListNode next, random;
* RandomListNode(int x) { this.label = x; }
* };
*/
public class Solution {
public RandomListNode copyRandomList(RandomListNode head) {
if (head == null) {
return null;
}
// step1
RandomListNode cur = head;
while (cur != null) {
RandomListNode node = new RandomListNode(cur.label);
node.next = cur.next;
cur.next = node;
cur = node.next;
}
// step2
cur = head;
while (cur != null) {
RandomListNode clone = cur.next;
if (cur.random != null) {
clone.random = cur.random.next;
}
cur = clone.next;
}
// step3
cur = head;
RandomListNode cloneHead = head.next;
while (cur.next != null) {
RandomListNode clone = cur.next;
cur.next = clone.next;
cur = clone;
}
return cloneHead;
}
}
…
139. 单词拆分
题目描述
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
- 拆分时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"] 输出: true 解释: 返回 true 因为"
applepenapple"
可以被拆分成"
apple pen apple"
。 注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: false
解法
Python3
Java
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
if (s == null || s.length() == 0) {
return false;
}
Set<String> words = new HashSet<>(wordDict);
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = i - 1; j > -1; j--) {
dp[i] = dp[j] && words.contains(s.substring(j, i));
if (dp[i]) {
break;
}
}
}
return dp[s.length()];
}
}
…
140. 单词拆分 II
题目描述
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
- 分隔时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例 1:
输入: s = "catsanddog
" wordDict =["cat", "cats", "and", "sand", "dog"]
输出:[ "cats and dog", "cat sand dog" ]
示例 2:
输入: s = "pineapplepenapple" wordDict = ["apple", "pen", "applepen", "pine", "pineapple"] 输出: [ "pine apple pen apple", "pineapple pen apple", "pine applepen apple" ] 解释: 注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog" wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: []
解法
Python3
Java
class Solution {
public List<String> wordBreak(String s, List<String> wordDict) {
return wordBreak(s,wordDict,new HashMap<>(16));
}
private List<String> wordBreak(String s, List<String> wordDict, HashMap<String, List<String>> map) {
List<String> list=new ArrayList<>();
if(map.containsKey(s)) return map.get(s);
if("".equals(s)){
list.add("");
return list;
}
for(String word:wordDict){
if(s.startsWith(word)){
List<String> res=wordBreak(s.substring(word.length()),wordDict,map);
for(String str:res){
list.add(word+("".equals(str) ?"":" ")+str);
}
}
}
map.put(s,list);
return list;
}
}
…
141. 环形链表
题目描述
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
解法
定义快慢指针 slow
、fast
,初始指向 head
。
快指针每次走两步,慢指针每次走一步,不断循环。当相遇时,说明链表存在环。如果循环结束依然没有相遇,说明链表不存在环。
Python3
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: ListNode) -> bool:
slow = fast = head
while fast and fast.next:
slow, fast = slow.next, fast.next.next
if slow == fast:
return True
return False
Java
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;
}
}
return false;
}
}
…
142. 环形链表 II
题目描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:tail connects to node index 1 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:tail connects to node index 0 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:no cycle 解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
解法
先利用快慢指针判断链表是否有环,没有环则直接返回 null
。
若链表有环,我们分析快慢相遇时走过的距离。
对于慢指针,走过的距离为 S=X+Y
①;快指针走过的距离为 2S=X+Y+N(Y+Z)
②。如下图所示,其中 N
表示快指针与慢指针相遇时在环中所走过的圈数,而我们要求的环入口,也即是 X
的距离:
我们根据式子 ①②,得出 X+Y=N(Y+Z)
=> X=(N-1)(Y+Z)+Z
。
当 N=1
(快指针在环中走了一圈与慢指针相遇) 时,X=(1-1)(Y+Z)+Z
,即 X=Z
。此时只要定义一个 p
指针指向头节点,然后慢指针与 p
开始同时走,当慢指针与 p
相遇时,也就到达了环入口,直接返回 p
即可。
当 N>1
时,也是同样的,说明慢指针除了走 Z
步,还需要绕 N-1
圈才能与 p
相遇。
Python3
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow = fast = head
has_cycle = False
while fast and fast.next:
slow, fast = slow.next, fast.next.next
if slow == fast:
has_cycle = True
break
if not has_cycle:
return None
p = head
while p != slow:
p, slow = p.next, slow.next
return p
Java
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head, fast = head;
boolean hasCycle = false;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
hasCycle = true;
break;
}
}
if (!hasCycle) {
return null;
}
ListNode p = head;
while (p != slow) {
p = p.next;
slow = slow.next;
}
return p;
}
}
…
143. 重排链表
题目描述
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
解法
先通过快慢指针找到链表中点,将链表划分为左右两部分。之后反转右半部分的链表,然后将左右两个链接依次连接即可。
Python3
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if head is None or head.next is None:
return
slow, fast = head, head.next
# 快慢指针找到链表中点
while fast and fast.next:
slow, fast = slow.next, fast.next.next
cur = slow.next
slow.next = None
pre = None
# cur 指向右半部分的链表,反转
while cur:
t = cur.next
cur.next = pre
pre = cur
cur = t
cur = head
# 将左右链表依次连接
while pre:
t1 = cur.next
cur.next = pre
cur = t1
t2 = pre.next
pre.next = t1
pre = t2
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null) {
return;
}
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode cur = slow.next;
slow.next = null;
ListNode pre = null;
while (cur != null) {
ListNode t = cur.next;
cur.next = pre;
pre = cur;
cur = t;
}
cur = head;
while (pre != null) {
ListNode t1 = cur.next;
cur.next = pre;
cur = t1;
ListNode t2 = pre.next;
pre.next = cur;
pre = t2;
}
}
}
…
144. 二叉树的前序遍历
题目描述
给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
解法
Python3
Java
// 递归版本
/*
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
preorderTraversal(root, list);
return list;
}
private void preorderTraversal(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
list.add(root.val);
preorderTraversal(root.left, list);
preorderTraversal(root.right, list);
}
}
*/
// 非递归版本
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (root != null) {
list.add(root.val);
if (root.right != null) {
stack.push(root.right);
}
if (root.left != null) {
stack.push(root.left);
}
if (!stack.isEmpty()) {
root = stack.pop();
} else {
break;
}
}
return list;
}
}
…
145. 二叉树的后序遍历
题目描述
给定一个二叉树,返回它的 后序 遍历。
示例:
输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
解法
Python3
Java
// 递归版本
/*
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
preorderTraversal(root, list);
return list;
}
private void preorderTraversal(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
list.add(root.val);
preorderTraversal(root.left, list);
preorderTraversal(root.right, list);
}
}
*/
// 非递归版本
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (root != null) {
list.add(root.val);
if (root.right != null) {
stack.push(root.right);
}
if (root.left != null) {
stack.push(root.left);
}
if (!stack.isEmpty()) {
root = stack.pop();
} else {
break;
}
}
return list;
}
}
…
146. LRU 缓存机制
题目描述
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get
和 写入数据 put
。
获取数据 get(key)
- 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value)
- 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // 返回 1 cache.put(3, 3); // 该操作会使得密钥 2 作废 cache.get(2); // 返回 -1 (未找到) cache.put(4, 4); // 该操作会使得密钥 1 作废 cache.get(1); // 返回 -1 (未找到) cache.get(3); // 返回 3 cache.get(4); // 返回 4
解法
Python3
Java
//双向链表的节点
class Node{
public int key;
public int val;
public Node pre;//指向前面的指针
public Node next;//指向后面的指针
public Node(int key,int value){
this.val = value;
this.key = key;
}
}
class LRUCache {
int capacity;//容量
Node head;//双向链表的头,维护这个指针,因为set,get时需要在头部操作
Node end;//双向链表的尾,set时,要是满了,需要将链表的最后一个节点remove
HashMap<Integer,Node> map = new HashMap<Integer,Node>();//hash表
public LRUCache(int capacity) {
this.capacity = capacity;
}
//添加,删除尾部,插入头部的操作
public void remove(Node node){
Node cur = node;
Node pre = node.pre;
Node post = node.next;
if(pre == null){//说明cur是头部节点
head = post;
}
else pre.next = post;//更新指针,删除
if(post == null){//说明cur是最后的节点
end = pre;
}
else post.pre = pre;
}
public void setHead(Node node){
//直接插入
node.next = head;
node.pre = null;
if(head != null) head.pre = node;//防止第一次插入时为空
head = node;
if(end==null) end = node;
}
public int get(int key) {
if(map.containsKey(key)){
//需要把对应的节点调整到头部
Node latest = map.get(key);
remove(latest);
setHead(latest);
//返回value
return latest.val;
}
else return -1;
}
public void put(int key, int value) {
if(map.containsKey(key)){//这个key原来存在
//只需要把key对应的node提到最前面,更新value
Node oldNode = map.get(key);
oldNode.val = value;
remove(oldNode);
setHead(oldNode);
}
else{
//这个key原来不存在,需要重新new出来
Node newNode = new Node(key,value);
//接下来要考虑容量
if(map.size() < capacity){
setHead(newNode);
map.put(key, newNode);
}
else{
//容量不够,需要先将map中,最不常使用的那个删除了删除
map.remove(end.key);
//接下来更新双向链表
remove(end);
setHead(newNode);
//放入新的
map.put(key, newNode);
}
}
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
…
147. 对链表进行插入排序
题目描述
对链表进行插入排序。
插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
- 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
- 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
- 重复直到所有输入数据插入完为止。
示例 1:
输入: 4->2->1->3 输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0 输出: -1->0->3->4->5
解法
遍历链表,每次将遍历到的结点 cur 与前一个结点 pre 进行值比较:
- 若结点 cur 的值比 pre 的大,说明当前 cur 已在正确的位置,直接往下遍历。
- 否则,从链表第一个结点开始遍历,将结点 cur 插入到正确的位置。
依次遍历,直至 cur 指向空,遍历结束。
Python3
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def insertionSortList(self, head: ListNode) -> ListNode:
if head is None or head.next is None:
return head
dummy = ListNode(head.val)
dummy.next = head
pre, cur = dummy, head
while cur:
if pre.val <= cur.val:
pre, cur = cur, cur.next
continue
p = dummy
while p.next.val <= cur.val:
p = p.next
t = cur.next
cur.next = p.next
p.next = cur
pre.next = t
cur = t
return dummy.next
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode insertionSortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode dummy = new ListNode(head.val);
dummy.next = head;
ListNode pre = dummy, cur = head;
while (cur != null) {
if (pre.val <= cur.val) {
pre = cur;
cur = cur.next;
continue;
}
ListNode p = dummy;
while (p.next.val <= cur.val) {
p = p.next;
}
ListNode t = cur.next;
cur.next = p.next;
p.next = cur;
pre.next = t;
cur = t;
}
return dummy.next;
}
}
…
148. 排序链表
题目描述
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3 输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0 输出: -1->0->3->4->5
解法
先用快慢指针找到链表中点,然后分成左右两个链表,递归排序左右链表。最后合并两个排序的链表即可。
Python3
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def sortList(self, head: ListNode) -> ListNode:
if head is None or head.next is None:
return head
slow, fast = head, head.next
while fast and fast.next:
slow, fast = slow.next, fast.next.next
t = slow.next
slow.next = None
l1, l2 = self.sortList(head), self.sortList(t)
dummy = ListNode()
cur = dummy
while l1 and l2:
if l1.val <= l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = l1 or l2
return dummy.next
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode t = slow.next;
slow.next = null;
ListNode l1 = sortList(head);
ListNode l2 = sortList(t);
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
cur.next = l1;
l1 = l1.next;
} else {
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1 == null ? l2 : l1;
return dummy.next;
}
}
…
149. 直线上最多的点数
题目描述
给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。
示例 1:
输入: [[1,1],[2,2],[3,3]] 输出: 3 解释: ^ | | o | o | o +-------------> 0 1 2 3 4
示例 2:
输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]] 输出: 4 解释: ^ | | o | o o | o | o o +-------------------> 0 1 2 3 4 5 6
解法
Python3
Java
class Solution {
public int maxPoints(Point[] points) {
if( points.length <= 2 ) return points.length;
int max = 2 ;
for( int i = 0 ; i < points.length ; i++ ){
int samePosition = 0;
int sameSlope = 1;
for( int j = i + 1 ; j < points.length ; j++ ){
long x1 = points[j].x - points[i].x;
long y1 = points[j].y - points[i].y;
if( x1 == 0 && y1 == 0 ){
samePosition++;
} else {
sameSlope++;
for(int k = j + 1 ; k < points.length ; k++ ){
long x2 = points[k].x - points[i].x;
long y2 = points[k].y - points[i].y;
if ( x1 * y2 == x2 * y1 ) sameSlope++;
}
}
if(max < (samePosition + sameSlope)) max = samePosition + sameSlope;
sameSlope = 1;
}
}
return max;
}
}
…
150. 逆波兰表达式求值
题目描述
根据逆波兰表示法,求表达式的值。
有效的运算符包括 +
, -
, *
, /
。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
- 整数除法只保留整数部分。
- 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: ["2", "1", "+", "3", "*"] 输出: 9 解释: ((2 + 1) * 3) = 9
示例 2:
输入: ["4", "13", "5", "/", "+"] 输出: 6 解释: (4 + (13 / 5)) = 6
示例 3:
输入: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"] 输出: 22 解释: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 17 + 5 = 22
解法
栈实现。
遍历数组,遇到数字则压入栈中,遇到运算符号,则从栈中弹出右、左操作数,运算过后,将结果压入栈中。
遍历结束后,返回栈中的唯一元素。
Python3
import operator
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
opt = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv
}
s = []
for token in tokens:
if token in opt:
s.append(int(opt[token](s.pop(-2), s.pop(-1))))
else:
s.append(int(token))
return s[0]
Java
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> s = new ArrayDeque<>();
int left, right;
for (String token : tokens) {
switch(token) {
case "+":
right = s.pop();
left = s.pop();
s.push(left + right);
break;
case "-":
right = s.pop();
left = s.pop();
s.push(left - right);
break;
case "*":
right = s.pop();
left = s.pop();
s.push(left * right);
break;
case "/":
right = s.pop();
left = s.pop();
s.push(left / right);
break;
default:
s.push(Integer.valueOf(token));
}
}
return s.pop();
}
}
…
151. 翻转字符串里的单词
题目描述
给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:
输入: "the sky is blue
" 输出: "blue is sky the
"
示例 2:
输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: "a good example" 输出: "example good a" 解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
说明:
- 无空格字符构成一个单词。
- 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
- 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
进阶:
请选用 C 语言的用户尝试使用 O(1) 额外空间复杂度的原地解法。
解法
Python3
Java
class Solution {
public String reverseWords(String s) {
int length = s.length();
if(length ==0)return s;
char[] res=new char[length];
int len=helper(s.toCharArray(), length -1,res,0,0);
return new String(res,0,len);
}
private int helper(char[] ch,int r,char[] res,int l,int len){
while(r>=0&&ch[r]==' ') r--;
if(r<0)return Math.max(0,len-1);
int rigth=r;
while(r>=0&&ch[r]!=' ') r--;
len+=rigth-r+1;
for(int left=r+1;left<=rigth;left++,l++) res[l] = ch[left];
if(l<res.length) res[l++] = ' ';
return helper(ch,r,res,l,len);
}
}
…
152. 乘积最大子序列
题目描述
给定一个整数数组 nums
,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
解法
考虑当前位置 i:
- 如果是一个负数的话,那么我们希望以它前一个位置结尾的某个段的积也是个负数,这样可以负负得正,并且我们希望这个积尽可能「负得更多」,即尽可能小。
- 如果是一个正数的话,我们更希望以它前一个位置结尾的某个段的积也是个正数,并且希望它尽可能地大。
因此,分别维护 fmax 和 fmin。
fmax(i) = max(nums[i], fmax(i - 1) * nums[i], fmin(i - 1) * nums[i])
fmin(i) = min(nums[i], fmax(i - 1) * nums[i], fmin(i - 1) * nums[i])
res = max(fmax(i)), i∈[0, n)
Python3
class Solution:
def maxProduct(self, nums: List[int]) -> int:
maxf = minf = nums[0]
res, n = nums[0], len(nums)
for i in range(1, n):
p, q = maxf, minf
maxf = max(nums[i], p * nums[i], q * nums[i])
minf = min(nums[i], p * nums[i], q * nums[i])
res = max(res, maxf)
return res
Java
class Solution {
public int maxProduct(int[] nums) {
int maxf = nums[0], minf = nums[0];
int res = nums[0], n = nums.length;
for (int i = 1; i < n; ++i) {
int p = maxf, q = minf;
maxf = Math.max(nums[i], Math.max(p * nums[i], q * nums[i]));
minf = Math.min(nums[i], Math.min(p * nums[i], q * nums[i]));
res = Math.max(res, maxf);
}
return res;
}
}
…
153. 寻找旋转排序数组中的最小值
题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
请找出其中最小的元素。
你可以假设数组中不存在重复元素。
示例 1:
输入: [3,4,5,1,2] 输出: 1
示例 2:
输入: [4,5,6,7,0,1,2] 输出: 0
解法
二分查找。
若 nums[m] > nums[r]
,说明最小值在 m 的右边,否则说明最小值在 m 的左边(包括 m)。
Python3
class Solution:
def findMin(self, nums: List[int]) -> int:
l, r = 0, len(nums) - 1
while l < r:
m = l + ((r - l) >> 1)
if nums[m] > nums[r]:
l = m + 1
else:
r = m
return nums[l]
Java
class Solution {
public int findMin(int[] nums) {
int l = 0, r = nums.length - 1;
while (l < r) {
int m = l + ((r - l) >> 1);
if (nums[m] > nums[r]) {
l = m + 1;
} else {
r = m;
}
}
return nums[l];
}
}
…
154. 寻找旋转排序数组中的最小值 II
题目描述
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
请找出其中最小的元素。
注意数组中可能存在重复的元素。
示例 1:
输入: [1,3,5] 输出: 1
示例 2:
输入: [2,2,2,0,1] 输出: 0
说明:
- 这道题是 寻找旋转排序数组中的最小值 的延伸题目。
- 允许重复会影响算法的时间复杂度吗?会如何影响,为什么?
解法
Python3
class Solution:
def findMin(self, nums: List[int]) -> int:
l, r = 0, len(nums) - 1
while l < r:
m = l + ((r - l) >> 1)
if nums[m] > nums[r]:
l = m + 1
elif nums[m] < nums[r]:
r = m
else:
r -= 1
return nums[l]
Java
class Solution {
public int findMin(int[] nums) {
int l = 0, r = nums.length - 1;
while (l < r) {
int m = l + ((r - l) >> 1);
if (nums[m] > nums[r]) {
l = m + 1;
} else if (nums[m] < nums[r]) {
r = m;
} else {
--r;
}
}
return nums[l];
}
}
…
155. 最小栈
题目描述
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
- push(x) -- 将元素 x 推入栈中。
- pop() -- 删除栈顶的元素。
- top() -- 获取栈顶元素。
- getMin() -- 检索栈中的最小元素。
示例:
MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); --> 返回 -3. minStack.pop(); minStack.top(); --> 返回 0. minStack.getMin(); --> 返回 -2.
解法
Python3
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.s = []
self.helper = []
def push(self, x: int) -> None:
self.s.append(x)
element = x if not self.helper or x < self.helper[-1] else self.helper[-1]
self.helper.append(element)
def pop(self) -> None:
self.s.pop()
self.helper.pop()
def top(self) -> int:
return self.s[-1]
def getMin(self) -> int:
return self.helper[-1]
# 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()
Java
class MinStack {
private Deque<Integer> s;
private Deque<Integer> helper;
/** initialize your data structure here. */
public MinStack() {
s = new ArrayDeque<>();
helper = new ArrayDeque<>();
}
public void push(int x) {
s.push(x);
int element = helper.isEmpty() || x < helper.peek() ? x : helper.peek();
helper.push(element);
}
public void pop() {
s.pop();
helper.pop();
}
public int top() {
return s.peek();
}
public int getMin() {
return helper.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
…
160. 相交链表
题目描述
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 输出:Reference of the node with value = 8 输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Reference of the node with value = 2 输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 输出:null 输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 解释:这两个链表不相交,因此返回 null。
注意:
- 如果两个链表没有交点,返回
null
. - 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
解法
定义两个指针,遍历时,当两个指针到达末尾的节点指向另一个链表的头部继续遍历,最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)。
两个指针等于移动了相同的距离,有交点就返回,无交点就是各走了两条指针的长度。
Python3
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if headA is None or headB is None:
return None
pA, pB = headA, headB
while pA != pB:
pA = pA.next if pA else headB
pB = pB.next if pB else headA
return pA
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode pA = headA, pB = headB;
while (pA != pB) {
pA = pA != null ? pA.next : headB;
pB = pB != null ? pB.next : headA;
}
return pA;
}
}
…
162. 寻找峰值
题目描述
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums
,其中 nums[i] ≠ nums[i+1]
,找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞
。
示例 1:
输入: nums = [1,2,3,1]
输出: 2
解释: 3 是峰值元素,你的函数应该返回其索引 2。
示例 2:
输入: nums = [
1,2,1,3,5,6,4]
输出: 1 或 5
解释: 你的函数可以返回索引 1,其峰值元素为 2;
或者返回索引 5, 其峰值元素为 6。
说明:
你的解法应该是 O(logN) 时间复杂度的。
解法
Python3
Java
class Solution {
public int findPeakElement(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if(nums[mid] < nums[mid + 1]) left = mid + 1;
else right = mid;
}
return left;
}
}
…
164. 最大间距
题目描述
给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值。
如果数组元素个数小于 2,则返回 0。
示例 1:
输入: [3,6,9,1] 输出: 3 解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
示例 2:
输入: [10] 输出: 0 解释: 数组元素个数小于 2,因此返回 0。
说明:
- 你可以假设数组中所有元素都是非负整数,且数值在 32 位有符号整数范围内。
- 请尝试在线性时间复杂度和空间复杂度的条件下解决此问题。
解法
Python3
Java
class Solution {
public int maximumGap(int[] nums) {
int length = nums.length;
if(length <2) return 0;
Arrays.sort(nums);
int max=0;
for(int i = 1; i< length; i++) max = Integer.max(nums[i] - nums[i - 1], max);
return max;
}
}
…
165. 比较版本号
题目描述
比较两个版本号 version1 和 version2。
如果 version1 > version2
返回 1
,如果 version1 < version2
返回 -1
, 除此之外返回 0
。
你可以假设版本字符串非空,并且只包含数字和 .
字符。
.
字符不代表小数点,而是用于分隔数字序列。
例如,2.5
不是“两个半”,也不是“差一半到三”,而是第二版中的第五个小版本。
你可以假设版本号的每一级的默认修订版号为 0
。例如,版本号 3.4
的第一级(大版本)和第二级(小版本)修订号分别为 3
和 4
。其第三级和第四级修订号均为 0
。
示例 1:
输入:version1
= "0.1",version2
= "1.1" 输出: -1
示例 2:
输入:version1
= "1.0.1",version2
= "1" 输出: 1
示例 3:
输入:version1
= "7.5.2.4",version2
= "7.5.3" 输出: -1
示例 4:
输入:version1
= "1.01",version2
= "1.001" 输出:0 解释:忽略前导零,“01” 和 “001” 表示相同的数字 “1”。
示例 5:
输入:version1
= "1.0",version2
= "1.0.0" 输出:0 解释:version1
没有第三级修订号,这意味着它的第三级修订号默认为 “0”。
提示:
- 版本字符串由以点 (
.
) 分隔的数字字符串组成。这个数字字符串可能有前导零。 - 版本字符串不以点开始或结束,并且其中不会有两个连续的点。
解法
Python3
Java
class Solution {
public int compareVersion(String version1, String version2) {
if(version1 == null || version2 == null) return 0;
char[] v1 = version1.toCharArray();
char[] v2 = version2.toCharArray();
for (int i = 0,j = 0;i < v1.length || j < v2.length;i++,j++){
int ver1 = 0, ver2 = 0;
for (;i<v1.length && v1[i]!='.';i++) ver1 = ver1 * 10 + v1[i] - '0';
for (;j<v2.length && v2[j]!='.';j++) ver2 = ver2 * 10 + v2[j] - '0';
if(ver1 < ver2) return -1;
else if(ver1 > ver2) return 1;
}
return 0;
}
}
…
166. 分数到小数
题目描述
给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。
如果小数部分为循环小数,则将循环的部分括在括号内。
示例 1:
输入: numerator = 1, denominator = 2 输出: "0.5"
示例 2:
输入: numerator = 2, denominator = 1 输出: "2"
示例 3:
输入: numerator = 2, denominator = 3 输出: "0.(6)"
解法
Python3
Java
class Solution {
public String fractionToDecimal(int numerator, int denominator) {
boolean minus = numerator < 0 && denominator > 0 || numerator > 0 && denominator < 0;
HashMap<Long, Integer> remains = new HashMap<>(16);
List<Long> resList = new ArrayList<>();
long n;
if(numerator > 0) n = numerator;
else if(numerator > Integer.MIN_VALUE) n = -numerator;
else n = Integer.MAX_VALUE + 1L;
long d;
if(denominator > 0) d = denominator;
else if(denominator > Integer.MIN_VALUE) d = -denominator;
else d = Integer.MAX_VALUE + 1L;
long r = n % d;
int index = 0 , loopPos = -1;
while(r != 0){
if(remains.containsKey(r)){
loopPos = remains.get(r);
break;
}
remains.put(r, ++index);
resList.add(Math.abs(n / d));
n = r;
n *= 10;
r = n % d;
}
resList.add(Math.abs(n / d));
StringBuilder res = new StringBuilder();
if(minus) res.append("-");
for(int i = 0; i < resList.size(); i++){
if(i == 1) res.append(".");
if(loopPos == i) res.append("(");
res.append(resList.get(i));
}
if(loopPos != -1) res.append(")");
return res.toString();
}
}
…
167. 两数之和 II - 输入有序数组
题目描述
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
- 返回的下标值(index1 和 index2)不是从零开始的。
- 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
解法
Python3
Java
class Solution {
public int[] twoSum(int[] numbers, int target) {
int l = 0, r = numbers.length - 1;
while(numbers[l]+numbers[r] != target) {
while(numbers[l] + numbers[r] > target) r --;
while(numbers[l] + numbers[r] < target) l ++;
}
return new int[] {l + 1, r + 1};
}
}
…
168. Excel 表列名称
题目描述
给定一个正整数,返回它在 Excel 表中相对应的列名称。
例如,
1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 -> AB ...
示例 1:
输入: 1 输出: "A"
示例 2:
输入: 28 输出: "AB"
示例 3:
输入: 701 输出: "ZY"
解法
Python3
Java
class Solution {
public String convertToTitle(int n) {
if (n < 0) {
return "";
}
StringBuilder sb = new StringBuilder();
while (n > 0) {
n--;
int temp = n % 26;
sb.insert(0,(char)(temp + 'A'));
n /= 26;
}
return sb.toString();
}
}
…
169. 多数元素
题目描述
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋
的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3] 输出: 3
示例 2:
输入: [2,2,1,1,1,2,2] 输出: 2
解法
Python3
Java
class Solution {
public int majorityElement(int[] nums) {
int count=1;
int res=nums[0];
for(int i=1; i<nums.length; i++){
if(res==nums[i])
count++;
else{
count--;
if(count==0)
res=nums[i+1];
}
}
return res;
}
}
…
171. Excel 表列序号
题目描述
给定一个Excel表格中的列名称,返回其相应的列序号。
例如,
A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ...
示例 1:
输入: "A" 输出: 1
示例 2:
输入: "AB" 输出: 28
示例 3:
输入: "ZY" 输出: 701
致谢:
特别感谢 @ts 添加此问题并创建所有测试用例。
解法
Python3
Java
class Solution {
public int titleToNumber(String s) {
char[] cs = s.toCharArray();
int n = 0;
int p = 1;
for (int i = cs.length-1; i >= 0; i--) {
n += (cs[i]-'A'+1)*p;
p *= 26;
}
return n;
}
}
…
172. 阶乘后的零
题目描述
给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 1:
输入: 3 输出: 0 解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5 输出: 1 解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
解法
Python3
Java
class Solution {
public int trailingZeroes(int n) {
int t = 0;
while (n >= 5) {
t += n / 5;
n /= 5;
}
return t;
}
}
…
173. 二叉搜索树迭代器
题目描述
实现一个二叉搜索树迭代器。你将使用二叉搜索树的根节点初始化迭代器。
调用 next()
将返回二叉搜索树中的下一个最小的数。
示例:
BSTIterator iterator = new BSTIterator(root); iterator.next(); // 返回 3 iterator.next(); // 返回 7 iterator.hasNext(); // 返回 true iterator.next(); // 返回 9 iterator.hasNext(); // 返回 true iterator.next(); // 返回 15 iterator.hasNext(); // 返回 true iterator.next(); // 返回 20 iterator.hasNext(); // 返回 false
提示:
next()
和hasNext()
操作的时间复杂度是 O(1),并使用 O(h) 内存,其中 h 是树的高度。- 你可以假设
next()
调用总是有效的,也就是说,当调用next()
时,BST 中至少存在一个下一个最小的数。
解法
Python3
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class BSTIterator {
Stack<TreeNode> vector = new Stack<>();
TreeNode current;
public BSTIterator(TreeNode root) {
current = root;
// 一直放入左儿子(左)
while (current != null) {
vector.push(current);
current = current.left;
}
}
/** @return whether we have a next smallest number */
public boolean hasNext() {
return !vector.isEmpty() || current != null;
}
/** @return the next smallest number */
public int next() {
// 一直放入左儿子(左)
while (current != null) {
vector.push(current);
current = current.left;
}
int ans = 0;
// 访问当前元素(中),把右儿子入栈(右)
if (!vector.isEmpty()) {
current = vector.pop();
ans = current.val;
current = current.right;
}
return ans;
}
}
/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator obj = new BSTIterator(root);
* int param_1 = obj.next();
* boolean param_2 = obj.hasNext();
*/
…
174. 地下城游戏
题目描述
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下
,则骑士的初始健康点数至少为 7。
说明:
<li> <p>骑士的健康点数没有上限。</p> </li> <li>任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。</li>
解法
Python3
Java
class Solution {
public int calculateMinimumHP(int[][] dungeon) {
int row = dungeon.length, column = dungeon[0].length;
int[][] dp = new int[row + 1][column + 1];
for (int i = 0;i <= row;i++) {
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
dp[row][column - 1] = dp[row - 1][column] = 1;
for (int i = row - 1;i > -1;i--) {
for (int j = column - 1;j > -1;j--) {
int min = Math.min(dp[i][j + 1], dp[i + 1][j]);
dp[i][j] = Math.max(min - dungeon[i][j], 1);
}
}
return dp[0][0];
}
}
…
179. 最大数
题目描述
给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。
示例 1:
输入:[10,2]
输出:210
示例 2:
输入:[3,30,34,5,9]
输出:9534330
说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。
解法
Python3
Java
public class Solution {
public String largestNumber(int[] nums) {
String[] strs = new String[nums.length];
for (int i = 0; i < strs.length; i++) {
strs[i] = nums[i] + "";
}
Arrays.sort(strs, new Comparator<String>() {
public int compare(String x, String y) {
return (y + x).compareTo(x + y);
}
});
if ("0".equals(strs[0])) {
return "0";
}
return String.join("", strs);
}
}
…
187. 重复的 DNA 序列
题目描述
所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。
编写一个函数来查找 DNA 分子中所有出现超过一次的 10 个字母长的序列(子串)。
示例:
输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" 输出:["AAAAACCCCC", "CCCCCAAAAA"]
解法
Python3
Java
class Solution {
public List<String> findRepeatedDnaSequences(String s) {
Map<String, Integer> map = new HashMap<>();
for (int i = 10; i <= s.length(); ++i) {
String sub = s.substring(i - 10, i);
map.put(sub, map.getOrDefault(sub, 0) + 1);
}
List<String> res = new ArrayList<>();
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() > 1) {
res.add(entry.getKey());
}
}
return res;
}
}
…
188. 买卖股票的最佳时机 IV
题目描述
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [2,4,1], k = 2 输出: 2 解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
示例 2:
输入: [3,2,6,5,0,3], k = 2 输出: 7 解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。 随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
解法
Python3
Java
class Solution {
public int maxProfit(int k, int[] prices) {
if (prices == null || prices.length == 0) {
return 0;
}
if(k >= prices.length) return maxProfit(prices);
int n = prices.length;
int[] l = new int[k + 1];
int[] g = new int[k + 1];
for (int i = 1; i < n; i++) {
int diff = prices[i] - prices[i - 1];
for (int j = k; j >= 1; j--) {
l[j] = Math.max(l[j], g[j - 1]) + diff;
g[j] = Math.max(l[j], g[j]);
}
}
return g[k];
}
public int maxProfit(int[] prices) {
// 只要有利润就卖,就是最优解。
int profit = 0;
for(int i = 1; i < prices.length; i++) {
if(prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1];
}
}
return profit;
}
}
…
189. 旋转数组
题目描述
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入:[1,2,3,4,5,6,7]
和 k = 3 输出:[5,6,7,1,2,3,4]
解释: 向右旋转 1 步:[7,1,2,3,4,5,6]
向右旋转 2 步:[6,7,1,2,3,4,5]
向右旋转 3 步:[5,6,7,1,2,3,4]
示例 2:
输入: [-1,-100,3,99]
和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的 原地 算法。
解法
若 k=3
,nums=[1,2,3,4,5,6,7]
。
先将 nums
整体翻转:[1,2,3,4,5,6,7]
-> [7,6,5,4,3,2,1]
再翻转 0~k-1
范围内的元素:[7,6,5,4,3,2,1]
-> [5,6,7,4,3,2,1]
最后翻转 k~n-1
范围内的元素,即可得到最终结果:[5,6,7,4,3,2,1]
-> [5,6,7,1,2,3,4]
Python3
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
k %= n
if n < 2 or k == 0:
return
nums[:] = nums[::-1]
nums[:k] = nums[:k][::-1]
nums[k:] = nums[k:][::-1]
Java
class Solution {
public void rotate(int[] nums, int k) {
if (nums == null) {
return;
}
int n = nums.length;
k %= n;
if (n < 2 || k == 0) {
return;
}
rotate(nums, 0, n - 1);
rotate(nums, 0, k - 1);
rotate(nums, k, n - 1);
}
private void rotate(int[] nums, int i, int j) {
while (i < j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
++i;
--j;
}
}
}
…
190. 颠倒二进制位
题目描述
颠倒给定的 32 位无符号整数的二进制位。
示例 1:
输入: 00000010100101000001111010011100 输出: 00111001011110000010100101000000 解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596, 因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
示例 2:
输入:11111111111111111111111111111101 输出:10111111111111111111111111111111 解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293, 因此返回 3221225471 其二进制表示形式为 10101111110010110010011101101001。
提示:
- 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
- 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 2 中,输入表示有符号整数
-3
,输出表示有符号整数-1073741825
。
进阶:
如果多次调用这个函数,你将如何优化你的算法?
解法
Python3
Java
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
int res = 0;
for (int i = 0; i < 31; i++, n>>=1, res<<=1) {
res |= (n&1);
}
res |= (n&1);
return res;
}
}
…
191. 位 1 的个数
题目描述
编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:
输入:00000000000000000000000010000000 输出:1 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:
输入:11111111111111111111111111111101 输出:31 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
提示:
- 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
- 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数
-3
。
进阶:
如果多次调用这个函数,你将如何优化你的算法?
解法
Python3
Java
public class Solution {
public int hammingWeight(int n) {
return Integer.bitCount(n);
}
}
…
198. 打家劫舍
题目描述
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1] 输出: 4 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入: [2,7,9,3,1] 输出: 12 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 偷窃到的最高金额 = 2 + 9 + 1 = 12 。
解法
Python3
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
n = len(nums)
if n == 1:
return nums[0]
pre, cur = nums[0], max(nums[0], nums[1])
for i in range(2, n):
t = max(pre + nums[i], cur)
pre, cur = cur, t
return cur
Java
class Solution {
public int rob(int[] nums) {
int n;
if (nums == null || (n = nums.length) == 0) {
return 0;
}
if (n == 1) {
return nums[0];
}
int pre = nums[0];
int cur = Math.max(nums[0], nums[1]);
for (int i = 2; i < n; ++i) {
int t = Math.max(pre + nums[i], cur);
pre = cur;
cur = t;
}
return cur;
}
}
…
199. 二叉树的右视图
题目描述
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例:
输入: [1,2,3,null,5,null,4] 输出: [1, 3, 4] 解释: 1 <--- / \ 2 3 <--- \ \ 5 4 <---
解法
Python3
Java
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> ans = new ArrayList<>();
robot(root, ans, 0);
return ans;
}
private void robot(TreeNode root, List<Integer> ans, int level) {
if (root == null) {
return;
}
if (ans.size() <= level) {
ans.add(root.val);
}
ans.set(level, root.val);
robot(root.left, ans, level + 1);
robot(root.right, ans, level + 1);
}
}
…