组合
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)
有以下几个原因:
-
可变性(Mutability)问题:
- 如果使用
res.add(path)
,那么当后续修改path
列表时,res
列表中对应的子列表也会被修改,因为它们共享同一个引用。 - 使用
new ArrayList<>(path)
可以创建path
的一个副本,这样就避免了共享引用的问题。
- 如果使用
-
安全性(Safety):
- 如果将
path
直接添加到res
列表中,那么以后如果不小心修改了path
列表,可能会导致res
列表中的数据也被修改,这可能会产生意料之外的结果。 - 创建副本可以确保
res
列表中的数据是安全的,不会被外部修改影响。
- 如果将
-
独立性(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因为每个都是单独的数组,直接遍历完就对了