leetcode47. 全排列 II(回溯算法-java)

265 篇文章 2 订阅
235 篇文章 0 订阅

leetcode47. 全排列 II

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/permutations-ii

题目描述

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]

示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:
1 <= nums.length <= 8
-10 <= nums[i] <= 10

解题思路

排列问题本身就是让你穷举元素的位置
但这个问题里,会有重复数字,因此我们要进行剪枝.
比如输入 nums = [2,2’,2’‘],产生的回溯树如下:,2’,2’’ 只是为了区分三个2.
他的全排列就是下图:
在这里插入图片描述
上面虽然有六个结果,但其实五个是重复的,实际只有一种情况.
我们要在排列时,对相同的情况进行剪枝.
如下图:
在这里插入图片描述
我们要把红色部分全部剪掉,因此就要有个标记,在没有重复的情况下,进行剪枝.
本题也是回溯算法的框架来做,只是要做好剪枝的问题.
再看一眼回溯算法的框架:
result = []
void process(选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择

代码演示

class Solution {
	//记录答案
    List<List<Integer>> ans = new ArrayList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        process(nums,0);
        return ans;
    }
	/**
	* 回溯算法
	*/
    public void process(int[]nums,int index){
        if(index == nums.length){
            ans.add(toList(nums));
            return ;
        }
        //用来标记相同的元素,
        HashMap<Integer,Boolean> flag = new HashMap<>();
        for(int i = index;i < nums.length;i++){
        //前面没有做出过选择,才进行选择
            if(!flag.containsKey(nums[i])){
            //已经做了选择,就加到标记里
                flag.put(nums[i],true);
                //全排列是对元素出现位置的穷举,因此我们把他交换到别的位置上,继续进行递归,
        		//来让他去出现在不同的位置上
        		//这一步就是做选择,
                swap(nums,i,index);
                process(nums,index + 1);
                //撤销选择
                swap(nums,i,index);
            }
        }
    }
    
	/**
	* 交换的方法
	*/
    public void swap(int[]nums,int i,int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
	/**
	* 数组转集合
	*/
    public List<Integer> toList(int[]nums){
        List<Integer> ans = new ArrayList<>();
        for(int a : nums){
            ans.add(a);
        }
        return ans;
    }
}

回溯算法专题

leetcode46. 全排列

leetcode39. 组合总和

leetcode216. 组合总和 III

leetcode90. 子集 II

leetcode40. 组合总和 II

leetcode77. 组合

leetcode78 子集

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值