• day24逆增子序列&全排列&全排列II(全排列问题:回溯三部曲)


            今天学习回溯的全排列问题,分为两种:一种包含重复元素,一种不包含重复元素。

    1.力扣491(逆增子序列

            本题因为每个元素只能使用一次,所以我们需要下标来记录带开始的位置,其次本题特殊的地方在于保证递归子序列的递增性,所以我们在遍历时要进行判断是否满足递增,不满足的直接continue。回溯三部曲:

    • 递归函数参数:本题求子序列,很明显一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。
        public void backtraveling(int[] nums,int startIndex)
    • 终止条件:本题其实类似求子集问题,也是要遍历树形结构找每一个节点,可以不加终止条件,startIndex每次都会加1,且本题的特殊是最少两个元素才能加入队列。
    1. if(path.size()>1){
    2. res.add(new ArrayList(path));
    3. }
    • 单层递归逻辑:跟求子集问题类似,只需要我们处理下不满足递增性的节点不加入即可
    1. int[] used = new int[201];
    2. for(int i=startIndex;i
    3. //树层去重
    4. if(!path.isEmpty()&&nums[i]1)||used[nums[i]+100]==1){
    5. continue;
    6. }
    7. path.add(nums[i]);
    8. used[nums[i]+100]=1;
    9. backtraveling(nums,i+1);
    10. path.remove(path.size()-1);
    11. }

    整体代码:

    1. List> res = new ArrayList();
    2. List path = new ArrayList();
    3. public List> findSubsequences(int[] nums) {
    4. backtraveling(nums,0);
    5. return res;
    6. }
    7. public void backtraveling(int[] nums,int startIndex){
    8. if(path.size()>1){
    9. res.add(new ArrayList(path));
    10. }
    11. int[] used = new int[201];
    12. for(int i=startIndex;i
    13. //树层去重
    14. if(!path.isEmpty()&&nums[i]1)||used[nums[i]+100]==1){
    15. continue;
    16. }
    17. path.add(nums[i]);
    18. used[nums[i]+100]=1;
    19. backtraveling(nums,i+1);
    20. path.remove(path.size()-1);
    21. }
    22. }

    2.力扣46(全排列)

            本题难点在于去重的操作,其他步骤和收集叶子节点的问题一样,只需要在尾节点处添加收集path即可,而我们怎么去重呢?也很简单,我们先定义一个used数组,我们在进行下次for循环时需要used【i】==true时,证明此元素使用过,就直接continue就可以达到去重了。回溯三部曲:

    • 递归函数参数:首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,也就是从0开始,所以处理排列问题就不用使用startIndex了。
        public void backtravling(int[] nums) 
    • 递归终止条件:当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。
    1. if(path.size()==nums.length){
    2. res.add(new ArrayList(path));
    3. return;
    4. }
    • 单层搜索的逻辑:因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次
    1. for(int i=0;i
    2. if(used[i]){
    3. continue;
    4. }
    5. path.add(nums[i]);
    6. used[i]=true;
    7. backtravling(nums);
    8. used[i] = false;
    9. path.remove(path.size()-1);
    10. }

    整体代码:

    1. List> res = new ArrayList();
    2. List path = new ArrayList();
    3. boolean[] used;
    4. public List> permute(int[] nums) {
    5. used = new boolean[nums.length];
    6. Arrays.fill(used,false);
    7. backtravling(nums);
    8. return res;
    9. }
    10. public void backtravling(int[] nums) {
    11. if(path.size()==nums.length){
    12. res.add(new ArrayList(path));
    13. return;
    14. }
    15. for(int i=0;i
    16. if(used[i]){
    17. continue;
    18. }
    19. path.add(nums[i]);
    20. used[i]=true;
    21. backtravling(nums);
    22. used[i] = false;
    23. path.remove(path.size()-1);
    24. }
    25. }

    3.力扣47(全排列II)

             本题是对上一个全排列问题的升级版,因为给我们的数组是包含重复元素的,所以我们不仅需要使用used【i】==true时跳过,我们还需要使用 i>0&&nums[i]==nums[i-1]&&!used[i-1]条件,若满足就跳过,也就是说我们在树层遍历时,碰到相同元素时,前面的元素的used【i-1】==false时跳过。

    整体代码:

    1. List> res = new ArrayList();
    2. List path = new ArrayList();
    3. boolean[] used;
    4. public List> permuteUnique(int[] nums) {
    5. used = new boolean[nums.length];
    6. Arrays.fill(used,false);
    7. Arrays.sort(nums);
    8. backtraveling(nums);
    9. return res;
    10. }
    11. public void backtraveling(int[] nums) {
    12. if(path.size()==nums.length){
    13. res.add(new ArrayList(path));
    14. return;
    15. }
    16. for(int i=0;i
    17. if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false){
    18. continue;
    19. }
    20. if(!used[i]){
    21. path.add(nums[i]);
    22. used[i] = true;
    23. backtraveling(nums);
    24. used[i] = false;
    25. path.remove(path.size()-1);
    26. }
    27. }
    28. }
  • 相关阅读:
    setup.py文件简介
    什么是多进程-多线程-多协程 ---- 文件系统
    C++智能指针
    普冉PY32系列(九) GPIO模拟和硬件SPI方式驱动无线收发芯片XL2400
    视频文件转gif图片Movie To GIF使用
    Learn-1
    React redux更新数据的诡异特征==》彻底掌握redux更新state机制的精髓
    【FFMPEG】解决截取MP4视频的中间段时,截取完成后前几帧视频卡住,但是有声音的情况
    操作系统MIT6.S081:P8->Multiprocessors and locking
    【网络安全】文件包含漏洞--使用session进行文件包含
  • 原文地址:https://blog.csdn.net/weixin_51558481/article/details/127411849