(1)定义方法,先序遍历保证顺序,把节点按顺序保存
(2)再for循环转成链表,一列都是往右排列
class Solution {
public void flatten(TreeNode root) {
List list = new ArrayList();
preorderTraversal(root, list);
int size = list.size();
// (2)for循环转成链表,一列都是往右排列
for(int i = 0; i < size - 1; i++){
TreeNode pre = list.get(i);
TreeNode cur = list.get(i + 1);
pre.right = cur;
pre.left = null;
}
}
// (1)定义方法,先序遍历保证顺序,把节点按顺序保存
public void preorderTraversal(TreeNode root, List list){
if(root != null){
list.add(root);
preorderTraversal(root.left, list);
preorderTraversal(root.right, list);
}
}
}
为什么不用.next 用.right
因为题目要求“展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null ”
一共定义两个方法,每个方法内部都用递归
(1)rootSum方法是计算从某一个节点开始,往下一共有多少条路径(起点固定,计算终点)
(2)pathSum是计算所有可能的起点节点,各自开始往下有多少条路径,的总和(列举所有起点)
其实就相当于两层for循环,一个计算起点,一个计算终点
以当前节点 p 为目标路径的起点递归向下进行搜索。假设当前的节点 p 的值为 val,我们对左子树和右子树进行递归搜索,对节点 p 的左孩子节点 p 求出 rootSum(p ,targetSum−val)
class Solution {
// (2)
public int pathSum(TreeNode root, long targetSum) {
if(root == null){
return 0;
}
int res = 0;
res += rootSum(root, targetSum);
res += pathSum(root.left, targetSum);
res += pathSum(root.right, targetSum);
return res;
}
// (1)
public int rootSum(TreeNode root, long targetSum){
if(root == null){
return 0;
}
int val = root.val;
int res = 0;
if(val == targetSum){
res++;
}
res += rootSum(root.left, targetSum - val);
res += rootSum(root.right, targetSum - val);
return res;
}
}
定义一个方法,递归求某个节点的最大贡献值。某个节点最大贡献值 = 该节点值 + 递归左节点最大贡献值 + 递归右节点最大贡献值
递归左节点最大贡献值 和 递归右节点最大贡献值 都只取大于0的
最大贡献值是例如,考虑如下二叉树。
-10
/ \
9 20
/ \
15 7
叶节点 9、15、7 的最大贡献值分别为 9、15、7
节点 20 的最大贡献值等于 20+max(15,7)=35,节点 −10 的最大贡献值等于 −10+max(9,35)=25
class Solution {
int maxSum = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
maxGain(root);
return maxSum;
}
public void maxGain(TreeNode node) {
if (node == null) {
return 0;
}
// 递归计算左右子节点的最大贡献值
// 只有在最大贡献值大于 0 时,才会选取对应子节点
int leftGain = Math.max(maxGain(node.left), 0);
int rightGain = Math.max(maxGain(node.right), 0);
// 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
int priceNewpath = node.val + leftGain + rightGain;
// 更新答案
maxSum = Math.max(maxSum, priceNewpath);
// 返回节点的最大贡献值
return node.val + Math.max(leftGain, rightGain);
}
}
为什么maxGain方法的返回值是return node.val + Math.max(leftGain, rightGain);而不是return maxSum?
确定返回值时,只看此方法,不要看上面的方法。
只看此方法的话,这个方法是一个递归方法,在方法内部递归调用这个方法
int leftGain = Math.max(maxGain(node.left), 0);
说明要调用maxGain,调用这个方法想获得什么值呢?
想获得的值就是原方法的返回值
这里想获得此节点的最大贡献值,而不是从根节点开始的整个数最大路径和
题目给了n,说明有n个左括号和n个右括号,需要排列组合
那就定义一个方法,记录左括号和右括号剩余的数量
如果剩余的相等,下一个就拼“(”
如果左括号剩余的小于右括号剩余的,下一个可以拼“(”或者“)”
【 左括号还剩大于0时拼“(” 左括号还剩等于0时拼“)” 】
可以通过手动模拟一些简单的 n 值(如 n = 1, 2, 3)来验证代码的正确性。
当 n = 1,应该生成 ()。
当 n = 2,应该生成 ()() 和 (())。
当 n = 3,应该生成 ()()(), (())(), ()(()), (()()), ((()))。
class Solution {
List res = new ArrayList<>();
public List generateParenthesis(int n) {
if(n <= 0){
return res;
}
getParenthesis("",n,n);
return res;
}
private void getParenthesis(String str,int left, int right) {
if(left == 0 && right == 0 ){
res.add(str);
return;
}
if(left == right){
//剩余左右括号数相等,下一个只能用左括号
getParenthesis(str+"(",left-1,right);
}else if(left < right){
//剩余左括号小于右括号,下一个可以用左括号也可以用右括号
if(left > 0){
getParenthesis(str+"(",left-1,right);
}
getParenthesis(str+")",left,right-1);
}
}
}
if(left == 0 && right == 0){
list.add(str);
return;
}
return必须加上,要不然会超出时间限制
不加return会在找到一个结果后,后面那些if继续判断
else if(left < right){
if(left > 0){
getParenthesis(str+"(", left - 1, right);
}
getParenthesis(str+")", left, right - 1);
}
这里的写法只能是这样,要不然会超出时间限制
不能写
else if(left < right){
if(left == 0){
getParenthesis(str+")", left, right - 1);
}
getParenthesis(str+"(", left - 1, right);
}