【算法】求全排列 回溯 交换 DFS JAVA

思路简述:

一个全排列其实就是一条把数组无重复遍历一遍的DFS过程

思路一:简单回溯,

1. 一个List存遍历路径,从第N个“结点”到第N+1个“结点”是只需要找一个未遍历的结点就行

2. 一个关键点在于查找 下一个可遍历“结点”, 可以用SET辅助List存放已遍历结点,List中存遍历书序(文中方法未用SET,复杂度较高,但是可以在Leetcode上AC);也可用一个数据结构完成:LinkedHashMap,即可保存插入顺序,也可O(1)判断是否存在某元素。

3. 回溯: 选中某一子“结点”递归下去之后,要回溯查找另一“子节点”,这就是回溯的过程,通过把某时刻路径中最后结点删除,添加下一“子节点”实现

代码

public List<List<Integer>> permute(int[] num) {
        List<List<Integer>> res = new LinkedList<List<Integer>>();
        if(num == null || num.length < 1) return res;
        bt(res, new ArrayList<Integer>(), 0, num);
        return res;
    }
    
    public void bt(List<List<Integer>> res, final List<Integer> cur, int now, int[] num){
        int length = num.length;
        if(cur.size() >= length) {
            res.add(new ArrayList<Integer>(){
                {
                    addAll(cur);
                }
            });
            return ;
        }
        for(int i = now; i < length || i % length < now; i++){//回溯
        	if(cur.contains(num[i % length])) continue;//判断回溯的元素是否已加入当前组合中
            cur.add(num[i % length]);
            bt(res, cur, (i  + 1)% length, num);
            cur.remove(cur.size() - 1);
        }
    }

思路二:

 基于思路一,不需要辅助List存放遍历路径,原数组就是遍历路径

每次寻找下一遍历结点的过程可以转化为,将后一结点交换到当前结点的过程

还原交换的过程就是回溯的过程

public List<List<Integer>> permute(int[] num) {
        List<List<Integer>> res = new LinkedList<List<Integer>>();
        if(num == null || num.length < 1) return res;
        bt(res, new ArrayList<Integer>(), 0, num);
        return res;
    }
    
    public void bt(List<List<Integer>> res, final List<Integer> cur, int now, final int[] num){
        int length = num.length;
        if(now >= length) {
            res.add(new ArrayList<Integer>(){
                {
                	for(int i: num)
                    add(i);
                }
            });
            return ;
        }
//        for(int i = now; i < length || i % length < now; i++){
//        	if(cur.contains(num[i % length])) continue;
//            cur.add(num[i % length]);
//            bt(res, cur, (i  + 1)% length, num);
//            cur.remove(cur.size() - 1);
//        }
        for(int i = now; i < length; i++){
        	swap(num, now, i);
        	bt(res, cur, now + 1, num);
        	swap(num, now, i);
        }
        
    }
    
    public void swap(int[] nums, int idx1, int idx2){
    	int temp = nums[idx1];
    	nums[idx1] = nums[idx2];
    	nums[idx2] = temp;
    }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值