草庐IT

LeetCode算法训练-回溯 491.递增子序列 46.全排列 47.全排列 II

cupxu 2023-03-28 原文

欢迎关注个人公众号:爱喝可可牛奶

LeetCode算法训练-回溯 491.递增子序列 46.全排列 47.全排列 II

LeetCode 491. 递增子序列

分析

找出并返回所有数组中不同的递增子序列

  1. 绝对不能先升序 绝对不能先升序 绝对不能先升序 这样会改变原有数组的结构

  2. 子序列中元素在数组中不一定相邻

  3. 只要叶子节点,也就是path,一满足条件,直接加入res

  4. 注意去重used[] 数组只针对当前节点的后序节点 要在回溯函数中定义 画回溯树一看便知

代码

class Solution {
    private LinkedList<Integer> path = new LinkedList<>();
    private List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backtracking(nums,0);
        return res;
    }

    private void backtracking (int[] nums, int start) {
        // 保证了能进入path的元素是升序的
        if (path.size() > 1) {
            res.add(new LinkedList<>(path));
            // 注意这里不要加return,要取树上的节点
        }
        // 元素值为used数组索引 只对同一行进行去重 
        int[] used = new int[201];
        for (int i = start; i < nums.length; i++) {
            // path 为空 当前元素小于path最后一个元素 或者这个元素在本层已经使用过了 跳过这个继续横向遍历 
            if (!path.isEmpty() && nums[i] < path.getLast() || (used[nums[i] + 100] == 1)) {
                    // 如果是break 应该是终止当前节点的横向遍历 进入递归
                    continue;
                }
            used[nums[i] + 100] = 1;
            path.add(nums[i]);
            backtracking(nums, i + 1);
            path.removeLast();
        }
    }
}

LeetCode 46. 全排列

分析

全排列,收集回溯树的叶子节点即可 注意终止条件要return

But 因为搜索过程每次都从第一个元素开始,要记录哪些元素已经使用过了 used[]数组应该是全局的

代码

class Solution {

    List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
    LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
    boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
        if (nums.length == 0){
            return result;
        }
        used = new boolean[nums.length];
        permuteHelper(nums);
        return result;
    }

    private void permuteHelper(int[] nums){
        if (path.size() == nums.length){
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++){
            if (used[i]){
                continue;
            }
            used[i] = true;
            path.add(nums[i]);
            permuteHelper(nums);
            path.removeLast();
            used[i] = false;
        }
    }
}

LeetCode 47. 全排列 II

分析

按任意顺序 返回所有不重复的全排列

涉及到如何去重 根据用例画一个回溯树看看

在横向遍历时,如果当前元素==前一个元素,continue;

难点:如何判断统一树层当前节点的前一个节点使用过 去看一下当前节点前一个节点的状态

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

代码

class Solution {

    List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
    LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
    
    public List<List<Integer>> permuteUnique(int[] nums) {
        if (nums.length == 0){
            return result;
        }
        // 得先排个序才能保证前后元素比较的正确性
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        permuteHelper(nums,used);
        return result;
    }

    private void permuteHelper(int[] nums, boolean[] used){
        if (path.size() == nums.length){
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++){
            // 一定要通过used保证nums[i-1]是树层上nums[i]的前一个元素
            if(i > 0 && nums[i] == nums[i-1] && !used[i-1]){
                continue;
            }
            if (!used[i]){
                used[i] = true;
                path.add(nums[i]);
                permuteHelper(nums,used);
                path.removeLast();
                used[i] = false;
            }

        }
    }
}

总结

  1. 组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果
  2. 理清回溯树树层、树枝的节点关系 for循环处理的是树层,递归调用函数处理的是树枝
  3. 如果没有startIndex来确定取的是数组中哪一个元素,used[]数组+for循环能间接确定这个元素是不是取过

有关LeetCode算法训练-回溯 491.递增子序列 46.全排列 47.全排列 II的更多相关文章

  1. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  2. ruby - 按值降序排列散列,然后按升序键入 ruby - 2

    我有这样的哈希trial_hash={"key1"=>1000,"key2"=>34,"key3"=>500,"key4"=>500,"key5"=>500,"key6"=>500}我按值降序排列:my_hash=trial_hash.sort_by{|k,v|v}.reverse我现在是这样理解的:[["key1",1000],["key4",500],["key5",500],["key6",500],["key3",500],["key2",34]]但我希望当值相同时按键的升序排序。我该怎么做?例如:上面的散列将以这种方式排序:[["key1",1000],["key3",500

  3. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  4. Python 刷Leetcode题库,顺带学英语单词(31) - 2

    ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem

  5. ruby - 如何在 ruby 中组合/排列? - 2

    我有一个熟悉的问题,看起来像是数学世界的排列/组合。如何通过ruby​​实现以下目标?badges="1-2-3"badge_cascade=[]badges.split("-").eachdo|b|badge_cascade["1","2","3"]ButIwantittobeis:=>["1","2","3","1-2","2-3","3-1","2-1","3-2","1-3","1-2-3","2-3-1","3-1-2"] 最佳答案 函数式方法:bs="1-2-3".split("-")strings=1.upto(bs.

  6. ruby - 重复排列 - 2

    我知道如何创建值数组的排列。例如:[*1..3].permutation(2)这导致以下六种排列:[1,2][1,3][2,1][2,3][3,1][3,2]但这个结果缺少三个排列,它们是相同值的组合,即:[1,1][2,2][3,3]如何获得所有排列,包括上面重复的排列? 最佳答案 尝试#repeated_permutation:[*1..3].repeated_permutation(3).to_a>pp[*1..3].repeated_permutation(3).to_a[[1,1,1],[1,1,2],[1,1,3],[1

  7. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  8. IDEA使用LeetCode插件 - 2

    前言我们习惯用idea编写、调试代码,在LeetCode上刷题时,如果能够在IDEA编写代码,并且做好代码管理,是一件事半功倍的事情。对于后续复习题目,做笔记也会非常便利。本文目的在于介绍LeetCodeEditor的使用,以及配置工具类,最终目录结构如下:note:放置笔记src:放置代码leetcode.editor.cn:插件LeetCodeEditor自动生成utils:自定义的工具包,可用于自动化输入测试用例,定义题目需要的类(结构体)out:运行测试时自动生成LeetCodeEditorGitHub:https://github.com/shuzijun/leetcode-edit

  9. ruby - 在 Ruby 中实现 Luhn 算法 - 2

    我一直在尝试用Ruby实现Luhn算法。我一直在执行以下步骤:该公式根据其包含的校验位验证数字,该校验位通常附加到部分帐号以生成完整帐号。此帐号必须通过以下测试:从最右边的校验位开始向左移动,每第二个数字的值加倍。将乘积的数字(例如,10=1+0=1、14=1+4=5)与原始数字的未加倍数字相加。如果总模10等于0(如果总和以零结尾),则根据Luhn公式该数字有效;否则无效。http://en.wikipedia.org/wiki/Luhn_algorithm这是我想出的:defvalidCreditCard(cardNumber)sum=0nums=cardNumber.to_s.s

  10. Ruby 斐波那契算法 - 2

    下面是我写的一个计算斐波那契数列中的值的方法:deffib(n)ifn==0return0endifn==1return1endifn>=2returnfib(n-1)+(fib(n-2))endend它工作到n=14,但在那之后我收到一条消息说程序响应时间太长(我正在使用repl.it)。有人知道为什么会这样吗? 最佳答案 Naivefibonacci进行了大量的重复计算-在fib(14)fib(4)中计算了很多次。您可以将内存添加到您的算法中以使其更快:deffib(n,memo={})ifn==0||n==1returnnen

随机推荐