代码随想录训练营第二十四天| 77. 组合 、 216.组合总和III 、17.电话号码的字母组合

组合

class Solution {
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> path=new LinkedList<>();
    //因为回溯函数返回的是空,所以是直接操作改变结果数组
    public List<List<Integer>> combine(int n, int k) {
        huisu(n, k, 1);
        return res;
        

    }
    //这题还是递归的过程
    void huisu(int n,int k,int index){
        if (path.size()==k) {
            res.add(new ArrayList<>(path));
            return;
            //这里是终止条件
            
        }
        for(int i=index;i<=n;i++){
            //这里的操作其实就是确定一个元素,组合剩下的元素
            path.add(i);
            huisu(n, k, i+1);
            path.remove(path.size()-1);//删掉最后一个
            //这个删掉最后一个要理一下,如果他就是结果,进入递归后发现大小满足,就直接存入结果然后return
            //然后正常情况下,到这一步说明是上一种情况完事了,要进入下一种情况了

        }

    }
}

这里好好理一下最后的这个删除最后一个元素的操作

res.add(new ArrayList<>(path));而不能是res.add(path)

Assistant

Poe

您提出了一个很好的问题。使用 res.add(new ArrayList<>(path)) 而不是 res.add(path) 有以下几个原因:

  1. 可变性(Mutability)问题:

    • 如果使用 res.add(path),那么当后续修改 path 列表时,res 列表中对应的子列表也会被修改,因为它们共享同一个引用。
    • 使用 new ArrayList<>(path) 可以创建 path 的一个副本,这样就避免了共享引用的问题。
  2. 安全性(Safety):

    • 如果将 path 直接添加到 res 列表中,那么以后如果不小心修改了 path 列表,可能会导致 res 列表中的数据也被修改,这可能会产生意料之外的结果。
    • 创建副本可以确保 res 列表中的数据是安全的,不会被外部修改影响。
  3. 独立性(Independence):

    • 使用副本可以使 res 列表中的子列表完全独立于 path 列表,它们不会相互影响。
    • 这样可以更好地控制和维护 res 列表中的数据。

综上所述,使用 res.add(new ArrayList<>(path)) 而不是 res.add(path) 可以更好地确保 res 列表的数据安全和独立性,避免由于引用共享导致的潜在问题。这是一个很好的编程实践。

这个问题你要注意

组合总和

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class day24_216_组合总和 {
    public static void main(String[] args) {
        
    }
    List<List<Integer>> res=new ArrayList<>();
    List<Integer> path=new LinkedList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        huisu(n, k, 1, 0);
        return res;

    }
    void huisu(int target,int k,int index,int nowsum){
        if (nowsum>target) {
            return;
            
        }
        if (nowsum==target&&path.size() == k) {
            res.add(new ArrayList<>(path));
            
        }
        for(int i=index;i<=9;i++){
            path.add(i);
            nowsum+=i;
            huisu(target, k, i+1, nowsum);
            path.remove(path.size()-1);
            nowsum-=i;
        }

    }
    
}

电话号码的字母组合

import java.util.ArrayList;
import java.util.List;

public class day24_17_电话号码的字母组合 {
    List<String> list = new ArrayList<>();
    String[] pipei={"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    //弄这个是为了匹配那两个数字对应的字母
    StringBuilder demo=new StringBuilder();

    public List<String> letterCombinations(String digits) {
        if (digits==null||digits.length()==0) {
            return list;
            
        }
        huisu(digits, digits.length(), 0);
        return list;

    }
    void huisu(String dig,int k,int n){
        //这里不需要index因为是两个独立的 数组,不是原来一个数组的组合问题一
        if (demo.length()==k) {
            list.add(demo.toString());
            //这里是判断如果大小符合了等于k就直接把这个字符串返回
            
        }
        String str = pipei[dig.charAt(n) - '0'];
        //这里是用了ascll码值
        for(int i=0;i<str.length();i++){
            demo.append(str.charAt(i));
            huisu(dig, k, n+1);
            demo.deleteCharAt(demo.length()-1);
            //这里是删除最后一个元素
        }

    }

    
}

这题不算难,不同的是,这里不用startindex因为每个都是单独的数组,直接遍历完就对了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值