LeetCode每日1题--47. 全排列 II

64 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情

前言

算法的重要性不言而喻!区分度高!

现在学习的门槛低了,只有能上网每个人都可以学编程!培训班6个月就可以培养出来能干活的人,你怎么从这些人中脱颖而出?没错!就是学算法,学一些底层和基础的东西。

说的功利点是为了竞争,卷死对手。真心话说就是能提高自己的基础能力,为技术可持续发展做好充分的准备!!!

提前入门学习书籍:CPrimerPlus、大话数据结构

image-20220705103735001

刷题网站

代码随想录 (programmercarl.com)

leetcode

我是按照代码随想录提供的刷题顺序进行刷题的,大家也可以去刷leetcode最热200道,都可以

刷题嘛,最重要的就是坚持了!!!

画图软件

OneNote

这个要经常用,遇见不懂的流程的话就拿它画一画!

笔记软件

Typoral

题目

leetcode.cn/problems/pe…

image.png

解析

这里其实也很简单,只不过是前几道题的结合

分别要对树层去重和树枝去重

树层去重采用

i > 0 && nums[i] == nums[i - 1]

那么树枝去重呢? 还是和全排列一样,通过used数组

used[i - 1] == false

image.png

回溯三部曲

  1. 递归参数

和上一题一样,把数组和记录结果的used数组传进去就行

private void backTrack(int[] nums, boolean[] used) {
  1. 递归终止的条件

终止条件就是

if (path.size() == nums.length) {
    result.add(new ArrayList<>(path));
    return;
}

和46题一样,收集够之后就开始添加进结果集合里

  1. 单层搜索的逻辑

单层搜索是最有讲究的,主要是去重这一块的逻辑

if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
    continue;
}

此为核心代码,既要保证树层去重也要保证树枝去重,且used[i - 1] == false也可以让值置为true

  • used[i - 1] == true,说明同⼀树⽀nums[i - 1]使⽤过

  • used[i - 1] == false,说明同⼀树层nums[i - 1]使⽤过

for (int i = 0; i < nums.length; i++) {
// used[i - 1] == true,说明同⼀树⽀nums[i - 1]使⽤过
// used[i - 1] == false,说明同⼀树层nums[i - 1]使⽤过
// 如果同⼀树层nums[i - 1]使⽤过则直接跳过
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
    continue;
}
//如果同⼀树⽀nums[i]没使⽤过开始处理
if (used[i] == false) {
    used[i] = true;//标记同⼀树⽀nums[i]使⽤过,防止同一树枝重复使用
    path.add(nums[i]);
    backTrack(nums, used);
    path.remove(path.size() - 1);//回溯,说明同⼀树层nums[i]使⽤过,防止下一树层重复
    used[i] = false;//回溯
}
}

完整代码

class Solution {
    //存放结果
    List<List<Integer>> result = new ArrayList<>();
    //暂存结果
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> permuteUnique(int[] nums) {
        boolean[] used = new boolean[nums.length];
        Arrays.fill(used, false);
        Arrays.sort(nums);
        backTrack(nums, used);
        return result;
    }

    private void backTrack(int[] nums, boolean[] used) {
        if (path.size() == nums.length) {
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            // 如果同⼀树层nums[i - 1]使⽤过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            //如果同⼀树⽀nums[i]没使⽤过开始处理
            if (used[i] == false) {
                used[i] = true;//标记同⼀树⽀nums[i]使⽤过,防止同一树枝重复使用
                path.add(nums[i]);
                backTrack(nums, used);
                path.remove(path.size() - 1);//回溯,说明同⼀树层nums[i]使⽤过,防止下一树层重复
                used[i] = false;//回溯
            }
        }
    }
}