代码随想录——113. 路径总和 II

/**
 * 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 List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new LinkedList<>();
        if (root == null) return res; 
        path.add(root.val);
        preorderdfs(root, targetSum-root.val, res, path);
        return res;
    }

    void  preorderdfs(TreeNode root, int targetSum,List<List<Integer>>res , List<Integer> path){
       if (root.left == null && root.right == null && targetSum == 0) {
            res.add(new ArrayList<>(path));
            return; 
        }
        if(root.left == null && root.right == null){
            return;
        }
        if(root.left != null){
            path.add(root.left.val);
            targetSum -=root.left.val;
            preorderdfs(root.left,targetSum,res,path);
            targetSum += root.left.val;
            path.remove(path.size() - 1);
        }
        if(root.right != null){
            path.add(root.right.val);
            targetSum -=root.right.val;
            preorderdfs(root.right,targetSum,res,path);
            targetSum += root.right.val;
            path.remove(path.size() - 1);
        }
        return;
    }
}

难点分析:

会把:
 if (root.left == null && root.right == null && targetSum == 0) {
            res.add(new ArrayList<>(path));
            return; 
        }
写成:
 if (root.left == null && root.right == null && targetSum == 0) {
            res.add(path);
            return; 
        }

错误原因:
在 Java 中,List 是一个接口,而具体的实现类有 ArrayListLinkedList 等。
当你调用 res.add(path) 时,实际上是将 path 这个列表对象添加到 res 中。
因此,当后续修改 path 时,也会影响到已经添加到 res 中的路径,因为它们是同一个列表对象的引用。

而当你使用 res.add(new ArrayList<>(path)) 时,首先通过 new ArrayList<>(path) 创建了一个新的列表对象,
将 path 中的元素拷贝到新列表中,并将新列表添加到 res 中。
这样做的结果是,res 中每个路径都是使用独立的列表对象表示的,它们不会相互影响。

为了更好地理解,让我们看一个简单的示例:


List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
path.add(1);
res.add(path);
path.add(2);
System.out.println(res);  // 输出 [[1, 2]]
在上面的示例中,当我们将 path 添加到 res 后,对 path 进行了修改,导致 res 中的路径也发生了改变。
这是因为 res 中存储的是对 path 对象的引用,而不是拷贝。

而如果我们改为使用 res.add(new ArrayList<>(path))List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
path.add(1);
res.add(new ArrayList<>(path));
path.add(2);
System.out.println(res);  // 输出 [[1]]

现在,由于我们使用了拷贝的方式将路径添加到 res 中,所以对 path 的修改不会影响到 res 中的路径。

因此,为了确保每个路径都是独立的,不受后续修改的影响,我们需要使用拷贝的方式将路径添加到结果列表 res 中。

list.remove()的原理是什么?
答:在 Java 中,List 接口提供了多个 remove 方法用于从列表中删除元素。
这些方法的底层实现原理取决于具体的 List 实现类(如 ArrayListLinkedList 等),但它们的基本原理可以概括如下:

 1. 根据索引删除元素:remove(int index) 方法用于根据索引删除列表中的元素。
 底层实现通常会移动其他元素来填补删除元素的位置,以保持列表的连续性。
 具体实现类可能使用数组或链表等数据结构来支持删除操作。
 对于 ArrayList,删除操作涉及将删除位置之后的元素向前移动一个位置;对于 LinkedList,删除操作涉及调整前一个节点和后一个节点的引用。
 
 2. 根据元素删除:remove(Object o) 方法用于根据元素值删除列表中的元素。
 底层实现会遍历列表,查找匹配的元素并将其删除。
 具体实现类可能使用循环或迭代器等方式进行查找和删除操作。
 在 ArrayList 中,遍历删除操作可能涉及多次移动元素,而在 LinkedList 中,遍历删除操作涉及调整节点的引用。

需要注意的是,remove 方法会删除列表中第一个匹配的元素。
如果列表中存在多个相同的元素,只有第一个匹配的元素会被删除。
如果要删除所有匹配的元素,可以使用循环或迭代器遍历列表,检查每个元素并删除匹配的元素。

另外,需要注意的是,在 ArrayList 中,删除元素的操作时间复杂度为 O(n),其中 n 是列表的大小。
这是因为删除元素后,需要移动后面的元素来填补空缺。
而在 LinkedList 中,删除元素的操作时间复杂度为 O(1),因为只需要调整相邻节点的引用。

总结起来,List 的 remove 方法根据索引或元素值删除元素,
具体实现类会根据底层的数据结构来进行相应的操作,
保证列表的连续性,并提供高效的删除操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值