现在来尝试将一系列的题目解决一下.
Path Sum
本题是 easy 难度的题目, 给定一个二叉树和一个和 sum, 判断是否有一条从根结点到叶子结点的路径, 使得路径上的结点的值之和与 sum 相等.
使用递归的思路 :
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null)
return false;
if (root.left == null && root.right == null && root.val == sum)
return true;
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
}
不使用递归, 使用栈的思路 :
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
Stack<TreeNode> nodes = new Stack<>();
Stack<Integer> nums = new Stack<>();
nodes.push(root);
nums.push(sum);
while(!nodes.isEmpty() && root != null) {
int value = nums.pop();
TreeNode top = nodes.pop();
if (top.left == null && top.right == null && value == top.val) {
return true;
}
if (top.left != null) {
nodes.push(top.left);
nums.push(value - top.val);
}
if (top.right != null) {
nodes.push(top.right);
nums.push(value - top.val);
}
}
return false;
}
}
这里的两个栈中的元素是相对应的, 一个结点对应一个数值, 当该结点为叶子结点, 且结点的值与栈中的值相等的时候, 那么就是存在的.
Path Sum ||
本题在上一题的要求上, 更进了一步, 不是判断是否存在这样的路径, 而是要将这些满足条件的路径记录下来. 其实这样的问题就是经典的 DFS 的问题了.
这里考虑的一个点是, 存放最终结果的 list 应该放在函数外面, 存放当前结果的也是, 所以这里的一个技巧是在给定的函数里面初始化需要的数据结构, 并用另一个函数调用.
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> result = new LinkedList<List<Integer>>();
List<Integer> currentResult = new LinkedList<>();
pathSumHelper(root, sum, result, currentResult);
return result;
}
public void pathSumHelper(TreeNode root, int sum, List<List<Integer>> result, List<Integer> currentResult) {
if (root == null)
return;
currentResult.add(root.val);
if (root.left == null && root.right == null && root.val == sum) {
result.add(new LinkedList(currentResult));
} else {
pathSumHelper(root.left, sum - root.val, result, currentResult);
pathSumHelper(root.right, sum - root.val, result, currentResult);
}
currentResult.remove(currentResult.size() - 1);
}
}
可以不用递归, 所有的递归都是用栈实现的, 所以这里可以使用栈来实现 : 这一类的题目基本都可以通过下面的方法来用栈实现.
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
if (root == null)
return result;
int pathSum = 0;
Stack<TreeNode> nodes = new Stack<>();
TreeNode curr = root;
TreeNode prev = null;
while(curr != null || !nodes.isEmpty()) {
// 找到当前结点的最左边的叶子结点
while(curr != null) {
nodes.push(curr);
path.add(curr.val);
pathSum += curr.val;
curr = curr.left;
}
// 这里使用 peek 而不是 pop, 这样如果有右子树也不用再放到栈中
curr = nodes.peek();
if (curr.right != null && curr.right != prev) {
curr = curr.right;
// 这里会跳到最外面那个 while 里面, 而不是跳到 if 外面, continue 和 break 都是针对循环的语句
continue;
}
if (curr.left == null && curr.right == null && pathSum == sum) {
result.add(new ArrayList<Integer>(path));
}
// 这条路走完了
nodes.pop();
prev = curr;
pathSum -= curr.val;
// 对应的结点也要去掉.
path.remove(path.size() - 1);
curr = null;
}
return result;
}
}
PathSum III
这里也是判断是否有加和等于给定值的路径, 但是这里的路径不是从根结点到叶子结点, 而是可以从任意结点开始, 任意结点结束, 只要这是一条向下的路径即可.
同样也可以用递归来完成, 对于每一个结点, 首先要考虑从该结点开始的路径是否存在满足条件的, 然后考虑该以该结点的左右子结点为开始结点的路径是否存在满足条件的.
这是一个典型的 DFS 的做法.
class Solution {
public int pathSum(TreeNode root, int sum) {
if (root == null) return 0;
return pathSumFrom(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);
}
public int pathSumFrom(TreeNode node, int sum) {
if (node == null)
return 0;
return (node.val == sum ? 1 : 0) + pathSumFrom(node.left, sum - node.val) + pathSumFrom(node.right, sum - node.val);
}
}
在和树相关的数据结构的试题中, 递归解法通常会用另一个函数来处理本结点, 然后再递归处理左右子结点.
来源:CSDN
作者:mrbm_lj
链接:https://blog.csdn.net/mrbm_lj/article/details/103684103