leetcode46 全排列
这里没有题解emm,象征性地指路官方题解
这里着重回溯法的两种传参方式
a. nums用流转化为list再加入到ans当中
执着了很久想要把int [] nums转化为Arraylist< Integer >然后加入结果
发现只能用流,具体可见这个
class Solution {
private List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> permute(int[] nums) {
if(nums.length == 0) return ans;
backTrack(nums,0);
return ans;
}
private void backTrack(int [] nums,int i){
if(i == nums.length - 1) {
//转化:
List<Integer> list = Arrays.stream(nums).boxed().collect(Collectors.toList());
ans.add(list);
}
int length = nums.length;
for(int j = i; j < length; j++){
swap(nums,i,j);
backTrack(nums,i+1);
swap(nums,i,j);
}
}
private void swap(int [] nums,int i , int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
b.传参数的时候直接传arraylist而不是数组
class Solution {
private List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> permute(int[] nums) {
if(nums.length == 0) return ans;
List<Integer> list = new ArrayList<Integer>();
for(int i : nums) list.add(i);
backTrack(nums,0,list);
return ans;
}
private void backTrack(int [] nums,int i,List<Integer> list){
if(i == nums.length - 1) {
ans.add(new ArrayList<>(list));/*!!!!!!!!!!!!!!!!!!!*/
}
int length = nums.length;
for(int j = i; j < length; j++){
Collections.swap(list, i, j);
backTrack(nums,i+1,list);
Collections.swap(list, i, j);
}
}
}
这里还有一个玄学
我第一次交的时候在上面标注感叹号的地方是这么写的:
if(i == nums.length - 1) {
ans.add(list);
}
完全知道是怎么肥四的就不用往下看啦
然后发现运行结果长这样:
人又懵了…
明明算法没有问题的嘛
改成ans.add(new ArrayList<>(list));
立马就过了
然后我又跑去康了源码
⬆️发现ArrayList的内部有一个Object数组用来存放数据
⬆️add就是把某个元素加到这个数组当中
然后就怀疑到了数组存放方式上
翻到了之前看深入理解jvm的笔记:
如果声明了对象数组,获得的将是对象引用的数组
还是深入理解jvm中的图:
数组在栈中,存放的是引用,而引用指向堆中对象的地址
所以明白啦:
再来看这个代码:
ans.add(new ArrayList<>(list));
ans.add(list);
它们俩的区别是:
第一个在堆中新建了一个对象,这个对象的内容和list相同,然后把这个新对象的地址加入到了ans中