lotus

贵有恒何必三更眠五更起 最无益只怕一日曝十日寒

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1846 随笔 :: 0 文章 :: 109 评论 :: 288万 阅读

1. 题目

 

 

 

读题

https://leetcode.cn/problems/permutations-ii/submissions/428949841/

 

考查点

这道题的考查点主要有以下几个:

- **回溯法**:回溯法是一种搜索所有可能解的方法,它的基本思想是从一个初始状态开始,每次尝试一个可能的选择,然后递归地搜索剩余的选择空间,如果发现当前的选择不能达到目标或者已经搜索完所有的选择,就回退到上一步,撤销当前的选择,继续尝试其他的选择,直到找到所有的解或者没有解为止。¹²
- **去重**:由于题目给定的序列可能包含重复的数字,所以在搜索全排列时,需要避免生成重复的结果。一种常用的方法是先对数组进行排序,然后在遍历数组时判断当前元素是否和前一个元素相同,如果相同且前一个元素没有被使用过,就跳过当前元素。这样可以保证相同的元素只会出现在同一位置一次。²³
- **编程技巧**:在实现回溯法时,需要注意一些编程技巧,比如如何定义和使用辅助变量(例如结果列表、布尔数组、当前序列等),如何递归地调用辅助函数,如何在递归返回后恢复原来的状态(例如移除当前元素、标记未使用等),以及如何优化代码的效率和可读性。²⁴

 

2. 解法

思路

回溯法是一种搜索所有可能解的方法,它的基本思想是从一个初始状态开始,每次尝试一个可能的选择,然后递归地搜索剩余的选择空间,如果发现当前的选择不能达到目标或者已经搜索完所有的选择,就回退到上一步,撤销当前的选择,继续尝试其他的选择,直到找到所有的解或者没有解为止。

对于这道题,我们可以把全排列看作是一个长度为n的序列,其中每个位置可以放置数组中的一个元素。我们从第一个位置开始,遍历数组中的每个元素,如果该元素没有被使用过,就把它放在第一个位置,并标记为已使用,然后递归地搜索剩余的n-1个位置。当搜索完所有的位置后,就得到了一个全排列,把它加入结果列表。然后回退到上一步,把当前元素从第一个位置移除,并标记为未使用,继续尝试其他的元素。为了避免重复的全排列,我们需要在遍历数组时判断当前元素是否和前一个元素相同,如果相同且前一个元素没有被使用过,就跳过当前元素。这样可以保证相同的元素只会出现在同一位置一次。

 

步骤来条理一下回溯法的思路:

  1. 定义一个结果列表,用来存放所有的全排列。
  2. 定义一个布尔数组,用来记录每个元素是否被使用过。
  3. 定义一个辅助函数,用来递归地搜索所有的全排列。
  4. 在辅助函数中,判断当前的序列是否已经达到了数组的长度,如果是,就把它加入结果列表,返回。
  5. 如果不是,就遍历数组中的每个元素,如果该元素没有被使用过,就把它加入当前的序列,并标记为已使用,然后递归地搜索剩余的位置。
  6. 在递归返回后,把当前元素从序列中移除,并标记为未使用,继续尝试其他的元素。
  7. 为了避免重复的全排列,我们需要在遍历数组时判断当前元素是否和前一个元素相同,如果相同且前一个元素没有被使用过,就跳过当前元素。
  8. 最后返回结果列表。

具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
    List<List<Integer>> list; // 存放结果
    boolean[] used; // 记录元素是否被使用过
 
    public List<List<Integer>> permuteUnique(int[] nums) {
        list = new ArrayList<>(); // 初始化结果列表
        used = new boolean[nums.length]; // 初始化布尔数组
        Arrays.sort(nums); // 对数组进行排序
        backtrack(new ArrayList<>(), nums); // 回溯
        return list; // 返回结果
    }
 
    private void backtrack(List<Integer> current, int[] nums) {
        if (current.size() == nums.length) { // 如果当前列表长度等于数组长度,说明找到了一个全排列
            list.add(new ArrayList<>(current)); // 把当前列表加入结果列表
        } else { // 否则,继续搜索
            for (int i = 0; i < nums.length; i++) { // 遍历数组中的每个元素
                if (used[i] || i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { // 如果元素已经被使用过,或者和前一个元素相同且前一个元素没有被使用过,跳过
                    continue;
                }
                used[i] = true; // 标记元素被使用过
                current.add(nums[i]); // 把元素加入当前列表
                backtrack(current, nums); // 回溯
                current.remove(current.size() - 1); // 把元素从当前列表移除
                used[i] = false; // 标记元素未被使用过
            }
        }
    }
}

  

3. 总结

posted on   白露~  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2019-04-29 Spring 框架用到的 9 个设计模式汇总!
2019-04-29 设计模式总结
2019-04-29 spring中的设计模式
2019-04-29 深入解析spring中用到的九种设计模式
点击右上角即可分享
微信分享提示