递归的用法(二)
递归就是把一个复杂的大问题,分解成一个个的小问题。递归是自调用。
每一个递归函数,都包含三个元素:
一:结束递归的逻辑
二:每一个递归处理的小问题的逻辑
三:进行方法自调用
首先,应该明确解题思路,问题分解成小问题的具体步骤,这涉及到元素一,二,三的使用,如果连问题分解都没有想好,那么无法完成递归的编码。所以,请切记。
第二,明确每一个小问题执行的步骤,
第三,明确每一个小问题在解决自身问题时,哪部分时清晰可以解决的,剩余的部分可以通过递归自调用解决的。
第四,明确每一个问题的子问题和当前的问题都是可以用同样的逻辑解决的。
没有重复项数字的全排列_牛客题霸_牛客网 (nowcoder.com)
以上例子就可以用递归算法解答
private void swap(ArrayList<Integer> num,int i1,int i2){ int temp = num.get(i1); num.set(i1,num.get(i2)); num.set(i2,temp); } public void recursion(ArrayList<ArrayList<Integer>> res,ArrayList<Integer> num,int index){ if (index == num.size() - 1) { ArrayList<Integer> integers = new ArrayList<>(Collections.nCopies(4,1)); Collections.copy(integers,num); res.add(integers); } else {
// 这个循环解决的问题是 对从index开始的所有元素进行全排列 for(int i = index; i < num.size(); i++){
// 第三个元素:明确每一个小问题,就是交换。完成一次和小标是i的元素交换,就是这个元素index这一次的排序。是一个简单的交换问题。
// 修改第index个元素(第index个元素相当余一个坑,需要用各种元素填完这个坑,再填下一个坑) swap(num,i,index);
// 对第index+1开始的元素进行进一步的复杂交换 recursion(res,num,index + 1);
// 回溯 swap(num,i,index); } } } public ArrayList<ArrayList<Integer>> permute(int[] num){ Arrays.sort(num); ArrayList<ArrayList<Integer>> res = new ArrayList<>(); ArrayList<Integer> nums = new ArrayList<>(); for (int i = 0; i < num.length; i++) { nums.add(num[i]); } recursion(res,nums,0); return res; }
就相当于有n个坑,对应有n个不同大小的皮球。每个坑能放的皮球。
可以分解成第n个坑放n种可能,第n-1个放n-1种可能
人前不露怯,
远足不露财,
内外当整洁,
自奉须俭约。