【探索-中级算法】全排列

在这里插入图片描述

参考自:https://my.oschina.net/u/3744313/blog/1923933

前提:没有重复数字的序列

解法一:

基于回溯的思想,借助一个辅助数组用于记录访问状态。
相关讲解视频:https://www.youtube.com/watch?v=oCGMwvKUQ_I

List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
    boolean[] map = new boolean[nums.length];
    dfs(nums, map, new ArrayList<>());
    return result;
}
public void dfs(int[] nums, boolean[] visited, List<Integer> tmp) {
    if (tmp.size() == nums.length)
        result.add(new ArrayList<>(tmp));
    else {
        // 否则,开始循环遍历,按照0,1,2..的顺序依次选择起点,然后遍历
        for (int i = 0; i < nums.length; i++) {
            if (visited[i])// 若该点已经被访问过了,则跳过访问下一个点
                continue;
            else {
            	// 若没被访问过,那么先标记为访问了,然后将其加入 tmp 中,
            	//等得到一个全排列的结果时加入到 result 中
                visited[i] = true;
                tmp.add(nums[i]);
                dfs(nums, visited, tmp);// 递归调用
                // 递归结束,还原当前位置的状态(即回溯),使得可以填充下一个元素,
                // 从而进行新的组合
                tmp.remove(tmp.size() - 1);
                // 访问标记还原,使得下次遍历还可以使用该元素
                visited[i] = false;
            }
        }
    }
}

例如:对于 [1,2,3],有如下部分过程示例

dfs(mums, visited, tmp())
	i = 0: v[0] = true
		  tmp = (1)
	      dfs(mums, visited, tmp(1))
		      i = 0: continue
			  i = 1: v[1] = true
	  		  tmp = (1, 2)
			  dfs(mums, visited, tmp(1, 2))
				  i = 0: continue
		  		  i = 1: continue
				  i = 2: v[2] = true
						 tmp = (1, 2, 3)
						 dfs(mums, visited, tmp(1, 2, 3))
					         add to result list
						 after tmp.remove(3 -1) tmp = (1, 2) 
						 v[2] = false
                  loop end
			  // 递归结束,还原 tmp[1],去掉 tmp(1, 2) 的第二个元素
			  // 即回溯,得到 tmp = (1),使得 tmp[1] 位置可以填充下一个元素
              after tmp.remove(2 -1) tmp = (1)  
			  v[1] = false 
	          i = 2: v[2] = true
			  ...
解法二:

交换解法,核心部分就是将各个位都与后面的每一个位都交换一次,并且这种交换是累积式的

public List<List<Integer>> permute(int[] nums) {
    helper(nums, 0);
    return result;
}

public void helper(int[] nums, int i){
    // 找到转置完成后的解,将其存入列表中
    if(i == nums.length - 1){
        List<Integer> list = new LinkedList<Integer
        for(int j = 0; j < nums.length; j++){
            list.add(nums[j]);
        }
        result.add(list);
    }
    // 将当前位置的数跟后面的数交换,并搜索解
    for(int j = i; j < nums.length; j++){
        swap(nums, i, j);// 交换位置
        helper(nums, i + 1);
        swap(nums, i, j);// 还原前面交换的位置
    }
}

private void swap(int[] nums, int i, int j){
    int tmp = nums[i];
    nums[i] = nums[j];
    nums[j] = tmp;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值