leetcode刷题day23|回溯算法Part02(39. 组合总和 、40.组合总和II、131.分割回文串)

news/2024/9/20 6:41:34 标签: 算法, leetcode, windows

39. 组合总和

思路:这个题与77. 组合的差异在于元素可以无限制重复被选取,那么只需要更改startIndex即可,每一层递归都可以从头选用元素。

回溯三部曲与77. 组合基本一致。

代码如下:

class Solution {
    List<List<Integer>> result=new ArrayList<>();
    List<Integer> path=new LinkedList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        backTracking(candidates,target,0);
        return result;
    }
    public void backTracking(int[] candidates, int target, int startIndex){
        if(target==0){
            result.add(new ArrayList(path));
            return;
        }else if(target<0){
            return;
        }
        for(int i=startIndex;i<candidates.length;i++){
            path.add(candidates[i]);
            backTracking(candidates,target-candidates[i],i);
            path.removeLast();
        }
    }
}

注意:如果是一个集合来求组合的话,需要startIndex,例如:77.组合,216.组合总和III;如果是多个集合取组合,各个集合之间相互不影响,不用startIndex。我一开始没用startIndex,导致递归过程(同一树枝上)中重复扫描前面的元素,结果出现了重复的组合。

40.组合总和II

思路:这个题跟39. 组合总和的区别在于给定数组中有重复元素,但要求最终的结果集合里面不能有重复数组。把回溯理解为树的结构,元素在同一树枝上是可以重复的,但在同一层上不能重复。要实现同一层上不重复出现需要对数组排序,当当前元素与上一次遍历的元素相同时跳过。

题目要求candidates 中的每个数字在每个组合中只能使用 一次 ,所以也要使用startIndex进行约束,每次递归函数调用i要加1。

代码如下:

class Solution {
    List<List<Integer>> result=new ArrayList<>();
    List<Integer> path=new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        backTracking(candidates,target,0);
        return result;
    }
    public void backTracking(int[] candidates,int target,int startIndex){
        if(target==0){
            result.add(new ArrayList(path));
            return;
        }else if(target<0){
            return;
        }
        for(int i=startIndex;i<candidates.length;i++){
            if(i>startIndex && candidates[i]==candidates[i-1]) continue;
            path.add(candidates[i]);
            backTracking(candidates,target-candidates[i],i+1);
            path.removeLast();
        }
    }
}

131.分割回文串

切割问题类似组合问题,例如对于字符串abcdef:

组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个…。
切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段…。

回溯三部曲:
1、递归函数参数:全局变量:数组path存放切割后回文的子串,二维数组result存放结果集。 递归函数参数:原字符串;startIndex,因为切割过的地方不能重复切割,和组合问题是一样的;新的StringBuilder字符串,存放切割后的字符子串,如果字符串是回文子串,将其加入path,递归进行下一次切割。
2、终止条件:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止条件。切割线即startIndex的位置。
3、单层搜索的逻辑:在for (int i = startIndex; i < s.size(); i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。首先判断这个子串是不是回文,如果是回文,就加入path中,path用来记录切割过的回文子串。

还有一个问题是如何判断回文子串:可以使用双指针法,一个指针从前向后,一个指针从后向前,如果前后指针所指向的元素是相等的,就是回文字符串了。

代码如下:

class Solution {
    List<List<String>> result=new ArrayList<>();
    List<String> path=new LinkedList<>();
    public List<List<String>> partition(String s) {
        backTracking(s,0,new StringBuilder());
        return result;
    }
    public void backTracking(String s,int startIndex,StringBuilder sb){
        if(startIndex==s.length()){
            result.add(new ArrayList(path));
            return;
        }
        for(int i=startIndex;i<s.length();i++){
            sb.append(s.charAt(i));
            if(check(sb)){
                path.add(sb.toString());
                backTracking(s,i+1,new StringBuilder());
                path.removeLast();
            }
        }
        
    }
    public boolean check(StringBuilder sb){
        for(int i=0;i<sb.length()/2;i++){
            if(sb.charAt(i)!=sb.charAt(sb.length()-1-i)) return false;
        }
        return true;
    }
}

这个题相对困难,要理解清楚怎么切割,怎么回溯,怎么存放。


http://www.niftyadmin.cn/n/5666786.html

相关文章

自定义复杂AntV/G6案例

一、效果图 二、源码 /** * * Author: me * CreatDate: 2024-08-22 * * Description: 复杂G6案例 * */ <template><div class"moreG6-wapper"><div id"graphContainer" ref"graphRef" class"graph-content"></d…

百度营销转化追踪(网页JS布码)

引言&#xff1a;使用百度营销api配置网站上各个模块组件的转化追踪&#xff0c;统计网站上的各组件模块点击等信息。 一、选择接入方式&#xff08;本文选择的是网页JS布码&#xff09; 参考文档&#xff1a;百度营销-商业开发者中心百度开发者中心是一个面向开发者的知识分享…

python画图|在3D图上画2D直方图(作图平面移动)

前期我们已经学习过2D和3D的直方图绘制&#xff1a; 二维常规直方图绘制&#xff1a;python画图|水平直方图绘制_绘制水平直方图-CSDN博客 二维极坐标直方图绘制&#xff1a;python画图|极坐标中画直方图_ax1.plot()怎么画直方图-CSDN博客 三维直方图绘制&#xff1a;python…

@Override -----好像删掉以后运行也没有问题。一个可有可无的注解?

简介 在 Java 中&#xff0c;Override 注解是可选的&#xff0c;但它提供了一些重要的好处。 虽然加不加 Override 注解在运行时的效果是一样的&#xff0c;但使用 Override 注解可以提高代码的可读性和维护性&#xff0c;并且可以在编译时捕获一些潜在的错误。 使用 O…

有效安全计划评估的基本指标

衡量安全计划成功与否的最有效指标是什么&#xff1f; 最直接的指标是&#xff1a;您的组织是否遭到入侵&#xff1f;如果答案是肯定的&#xff0c;那么显然还有工作要做。如果答案是否定的&#xff0c;那么您的状况就更好了——但情况比这更复杂。 即使您没有遭到入侵&#…

CSS的三种基本选择器

使用CSS控制网页格式有行内法&#xff0c;内嵌式&#xff0c;链接式&#xff0c;导入式等方法 这里将采用内嵌式的方法书写 内嵌法就是通过<style>标记将样式定义在HTML的文件头部中 1.标记选择器 标记选择器特点&#xff1a;定义了标记选择器之后&#xff0c;网页中…

『功能项目』QFrameWorkBug修改器界面【65】

我们打开上一篇64QFrameWork道具栏物品生成的项目&#xff0c; 本章要做的事情是做一个道具bug调试面板&#xff0c;可以增加主角属性&#xff0c;可以增加道具的功能 首先创建一个空物体&#xff08;钉子&#xff09; 按住Alt键将空物体钉到左侧 重命名为Left 创建Button、Im…

【计算机基础题目】Linux系统中文件权限 字母权限和数字权限的相互转换

创作日志&#xff1a; 很久之前对这个略有了解&#xff0c;但是现在完全忘记了&#xff0c;看到这类题目一脸懵逼&#xff0c;现在系统复习下。 1、权限的数字表示&#xff08;3位&#xff09; 在Linux系统中&#xff0c;文件权限由一个三位的八进制数表示&#xff0c;每一位代…