代码随想录-算法训练营day27【回溯03:组合总和、分割回文串】

本文主要是介绍代码随想录-算法训练营day27【回溯03:组合总和、分割回文串】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客

第七章 回溯算法part03● 39. 组合总和
● 40.组合总和II
● 131.分割回文串详细布置 39. 组合总和 本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制题目链接/文章讲解:https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html 
视频讲解:https://www.bilibili.com/video/BV1KT4y1M7HJ  40.组合总和II 本题开始涉及到一个问题了:去重。注意题目中给我们 集合是有重复元素的,那么求出来的 组合有可能重复,但题目要求不能有重复组合。 题目链接/文章讲解:https://programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html   
视频讲解:https://www.bilibili.com/video/BV12V4y1V73A131.分割回文串  本题较难,大家先看视频来理解 分割问题,明天还会有一道分割问题,先打打基础。 https://programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html  
视频讲解:https://www.bilibili.com/video/BV1c54y1e7k6  往日任务
● day 1 任务以及具体安排:https://docs.qq.com/doc/DUG9UR2ZUc3BjRUdY  
● day 2 任务以及具体安排:https://docs.qq.com/doc/DUGRwWXNOVEpyaVpG  
● day 3 任务以及具体安排:https://docs.qq.com/doc/DUGdqYWNYeGhlaVR6 
● day 4 任务以及具体安排:https://docs.qq.com/doc/DUFNjYUxYRHRVWklp 
● day 5 周日休息
● day 6 任务以及具体安排:https://docs.qq.com/doc/DUEtFSGdreWRuR2p4 
● day 7 任务以及具体安排:https://docs.qq.com/doc/DUElCb1NyTVpXa0Jj 
● day 8 任务以及具体安排:https://docs.qq.com/doc/DUGdsY2JFaFhDRVZH 
● day 9 任务以及具体安排:https://docs.qq.com/doc/DUHVXSnZNaXpVUHN4 
● day 10 任务以及具体安排:https://docs.qq.com/doc/DUElqeHh3cndDbW1Q 
●day 11 任务以及具体安排:https://docs.qq.com/doc/DUHh6UE5hUUZOZUd0 
●day 12 周日休息 
●day 13 任务以及具体安排:https://docs.qq.com/doc/DUHNpa3F4b2dMUWJ3 
●day 14 任务以及具体安排:https://docs.qq.com/doc/DUHRtdXZZSWFkeGdE 
●day 15 任务以及具体安排:https://docs.qq.com/doc/DUHN0ZVJuRmVYeWNv 
●day 16 任务以及具体安排:https://docs.qq.com/doc/DUHBQRm1aSWR4T2NK 
●day 17 任务以及具体安排:https://docs.qq.com/doc/DUFpXY3hBZkpabWFY 
●day 18 任务以及具体安排:https://docs.qq.com/doc/DUFFiVHl3YVlReVlr 
●day 19 周日休息
●day 20 任务以及具体安排:https://docs.qq.com/doc/DUGFRU2V6Z1F4alBH  
●day 21 任务以及具体安排:https://docs.qq.com/doc/DUHl2SGNvZmxqZm1X 
●day 22 任务以及具体安排:https://docs.qq.com/doc/DUHplVUp5YnN1bnBL  
●day 23 任务以及具体安排:https://docs.qq.com/doc/DUFBUQmxpQU1pa29C 
●day 24 任务以及具体安排:https://docs.qq.com/doc/DUEhsb0pUUm1WT2NP  
●day 25 任务以及具体安排:https://docs.qq.com/doc/DUExTYXVzU1BiU2Zl

目录

0039_组合总和

0040_组合总和II

0131_分割回文串


0039_组合总和

package com.question.solve.leetcode.programmerCarl2._08_backtrackingAlgorithms;import java.util.*;public class _0039_组合总和 {
}class Solution0039 {//剪枝优化public List<List<Integer>> combinationSum(int[] candidates, int target) {List<List<Integer>> res = new ArrayList<>();Arrays.sort(candidates); //先进行排序backtracking(res, new ArrayList<>(), candidates, target, 0, 0);return res;}public void backtracking(List<List<Integer>> res, List<Integer> path, int[] candidates, int target, int sum, int idx) {//找到了数字和为 target 的组合if (sum == target) {res.add(new ArrayList<>(path));return;}for (int i = idx; i < candidates.length; i++) {//如果 sum + candidates[i] > target 就终止遍历if (sum + candidates[i] > target) break;path.add(candidates[i]);backtracking(res, path, candidates, target, sum + candidates[i], i);path.remove(path.size() - 1); //回溯,移除路径 path 最后一个元素}}
}class Solution0039_2 {public List<List<Integer>> combinationSum(int[] candidates, int target) {int len = candidates.length;List<List<Integer>> res = new ArrayList<>();if (len == 0) {return res;}Deque<Integer> path = new ArrayDeque<>();dfs(candidates, 0, len, target, path, res);return res;}/*** @param candidates 候选数组* @param begin      搜索起点* @param len        冗余变量,是 candidates 里的属性,可以不传* @param target     每减去一个元素,目标值变小* @param path       从根结点到叶子结点的路径,是一个栈* @param res        结果集列表*/private void dfs(int[] candidates, int begin, int len, int target, Deque<Integer> path, List<List<Integer>> res) {//target 为负数和 0 的时候,不再产生新的孩子结点if (target < 0) {return;}if (target == 0) {res.add(new ArrayList<>(path));return;}//重点理解这里从 begin 开始搜索的语意for (int i = begin; i < len; i++) {path.addLast(candidates[i]);//注意:由于每一个元素可以重复使用,下一轮搜索的起点依然是 i,这里非常容易弄错dfs(candidates, i, len, target - candidates[i], path, res);//状态重置path.removeLast();}}
}

0040_组合总和II

package com.question.solve.leetcode.programmerCarl2._08_backtrackingAlgorithms;import java.util.*;public class _0040_组合总和II {public static void main(String[] args) {int[] candidates = new int[]{10, 1, 2, 7, 6, 1, 5};int target = 8;Solution0040_3 solution = new Solution0040_3();List<List<Integer>> res = solution.combinationSum2(candidates, target);System.out.println("输出 => " + res);}
}class Solution0040 {//使用标记数组LinkedList<Integer> path = new LinkedList<>();List<List<Integer>> ans = new ArrayList<>();boolean[] used;int sum = 0;public List<List<Integer>> combinationSum2(int[] candidates, int target) {used = new boolean[candidates.length];//加标志数组,用来辅助判断同层节点是否已经遍历Arrays.fill(used, false);//为了将重复的数字都放到一起,所以先进行排序Arrays.sort(candidates);backTracking(candidates, target, 0);return ans;}private void backTracking(int[] candidates, int target, int startIndex) {if (sum == target) {ans.add(new ArrayList(path));}for (int i = startIndex; i < candidates.length; i++) {if (sum + candidates[i] > target) {break;}//出现重复节点,同层的第一个节点已经被访问过,所以直接跳过if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {continue;}used[i] = true;sum += candidates[i];path.add(candidates[i]);//每个节点仅能选择一次,所以从下一位开始backTracking(candidates, target, i + 1);used[i] = false;sum -= candidates[i];path.removeLast();}}
}class Solution0040_2 {//不使用标记数组List<List<Integer>> res = new ArrayList<>();LinkedList<Integer> path = new LinkedList<>();int sum = 0;public List<List<Integer>> combinationSum2(int[] candidates, int target) {//为了将重复的数字都放到一起,所以先进行排序Arrays.sort(candidates);backTracking(candidates, target, 0);return res;}private void backTracking(int[] candidates, int target, int start) {if (sum == target) {res.add(new ArrayList<>(path));return;}for (int i = start; i < candidates.length && sum + candidates[i] <= target; i++) {//正确剔除重复解的办法//跳过同一树层使用过的元素if (i > start && candidates[i] == candidates[i - 1]) {continue;}sum += candidates[i];path.add(candidates[i]);// i+1 代表当前组内元素只选取一次backTracking(candidates, target, i + 1);int temp = path.getLast();sum -= temp;path.removeLast();}}
}class Solution0040_3 {public List<List<Integer>> combinationSum2(int[] candidates, int target) {int len = candidates.length;List<List<Integer>> res = new ArrayList<>();if (len == 0) {return res;}//关键步骤Arrays.sort(candidates);Deque<Integer> path = new ArrayDeque<>(len);dfs(candidates, len, 0, target, path, res);return res;}/*** @param candidates 候选数组* @param len        冗余变量* @param begin      从候选数组的 begin 位置开始搜索* @param target     表示剩余,这个值一开始等于 target,基于题目中说明的"所有数字(包括目标数)都是正整数"这个条件* @param path       从根结点到叶子结点的路径* @param res*/private void dfs(int[] candidates, int len, int begin, int target, Deque<Integer> path, List<List<Integer>> res) {if (target == 0) {res.add(new ArrayList<>(path));return;}for (int i = begin; i < len; i++) {//大剪枝:减去 candidates[i] 小于 0,减去后面的 candidates[i + 1]、candidates[i + 2] 肯定也小于 0,因此用 breakif (target - candidates[i] < 0) {break;}//小剪枝:同一层相同数值的结点,从第 2 个开始,候选数更少,结果一定发生重复,因此跳过,用 continueif (i > begin && candidates[i] == candidates[i - 1]) {continue;}path.addLast(candidates[i]);//调试语句 ①//System.out.println("递归之前 => " + path + ",剩余 = " + (target - candidates[i]));// 因为元素不可以重复使用,这里递归传递下去的是 i + 1 而不是 idfs(candidates, len, i + 1, target - candidates[i], path, res);path.removeLast();//调试语句 ②//System.out.println("递归之后 => " + path + ",剩余 = " + (target - candidates[i]));}}
}

0131_分割回文串

package com.question.solve.leetcode.programmerCarl2._08_backtrackingAlgorithms;import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;public class _0131_分割回文串 {
}class Solution0131 {List<List<String>> lists = new ArrayList<>();Deque<String> deque = new LinkedList<>();public List<List<String>> partition(String s) {backTracking(s, 0);return lists;}private void backTracking(String s, int startIndex) {//如果起始位置大于s的大小,说明找到了一组分割方案if (startIndex >= s.length()) {lists.add(new ArrayList(deque));return;}for (int i = startIndex; i < s.length(); i++) {//如果是回文子串,则记录if (isPalindrome(s, startIndex, i)) {String str = s.substring(startIndex, i + 1);deque.addLast(str);} else {continue;}//起始位置后移,保证不重复backTracking(s, i + 1);deque.removeLast();}}//判断是否是回文串private boolean isPalindrome(String s, int startIndex, int end) {for (int i = startIndex, j = end; i < j; i++, j--) {if (s.charAt(i) != s.charAt(j)) {return false;}}return true;}
}class Solution0131_2 {//回溯+动态规划优化回文串判断List<List<String>> result;LinkedList<String> path;boolean[][] dp;public List<List<String>> partition(String s) {result = new ArrayList<>();char[] str = s.toCharArray();path = new LinkedList<>();dp = new boolean[str.length + 1][str.length + 1];isPalindrome(str);backtracking(s, 0);return result;}public void backtracking(String str, int startIndex) {if (startIndex >= str.length()) {//如果起始位置大于s的大小,说明找到了一组分割方案result.add(new ArrayList<>(path));} else {for (int i = startIndex; i < str.length(); ++i) {if (dp[startIndex][i]) {//是回文子串,进入下一步递归//先将当前子串保存入pathpath.addLast(str.substring(startIndex, i + 1));//起始位置后移,保证不重复backtracking(str, i + 1);path.pollLast();} else {//不是回文子串,跳过continue;}}}}//通过动态规划判断是否是回文串,参考动态规划篇 52 回文子串public void isPalindrome(char[] str) {for (int i = 0; i <= str.length; ++i) {dp[i][i] = true;}for (int i = 1; i < str.length; ++i) {for (int j = i; j >= 0; --j) {if (str[j] == str[i]) {if (i - j <= 1) {dp[j][i] = true;} else if (dp[j + 1][i - 1]) {dp[j][i] = true;}}}}}
}

这篇关于代码随想录-算法训练营day27【回溯03:组合总和、分割回文串】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/947426

相关文章

利用c++判断水仙花数并输出示例代码

《利用c++判断水仙花数并输出示例代码》水仙花数是指一个三位数,其各位数字的立方和恰好等于该数本身,:本文主要介绍利用c++判断水仙花数并输出的相关资料,文中通过代码介绍的非常详细,需要的朋友可以... 以下是使用C++实现的相同逻辑代码:#include <IOStream>#include <vec

Java 接口定义变量的示例代码

《Java接口定义变量的示例代码》文章介绍了Java接口中的变量和方法,接口中的变量必须是publicstaticfinal的,用于定义常量,而方法默认是publicabstract的,必须由实现类... 在 Java 中,接口是一种抽象类型,用于定义类必须实现的方法。接口可以包含常量和方法,但不能包含实例

使用Redis实现会话管理的示例代码

《使用Redis实现会话管理的示例代码》文章介绍了如何使用Redis实现会话管理,包括会话的创建、读取、更新和删除操作,通过设置会话超时时间并重置,可以确保会话在用户持续活动期间不会过期,此外,展示了... 目录1. 会话管理的基本概念2. 使用Redis实现会话管理2.1 引入依赖2.2 会话管理基本操作

mybatis-plus分表实现案例(附示例代码)

《mybatis-plus分表实现案例(附示例代码)》MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生,:本文主要介绍my... 目录文档说明数据库水平分表思路1. 为什么要水平分表2. 核心设计要点3.基于数据库水平分表注意事项示例

Nginx服务器部署详细代码实例

《Nginx服务器部署详细代码实例》Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,:本文主要介绍Nginx服务器部署的相关资料,文中通过代码... 目录Nginx 服务器SSL/TLS 配置动态脚本反向代理总结Nginx 服务器Nginx是一个‌高性

HTML5的input标签的`type`属性值详解和代码示例

《HTML5的input标签的`type`属性值详解和代码示例》HTML5的`input`标签提供了多种`type`属性值,用于创建不同类型的输入控件,满足用户输入的多样化需求,从文本输入、密码输入、... 目录一、引言二、文本类输入类型2.1 text2.2 password2.3 textarea(严格

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

MyBatis中的两种参数传递类型详解(示例代码)

《MyBatis中的两种参数传递类型详解(示例代码)》文章介绍了MyBatis中传递多个参数的两种方式,使用Map和使用@Param注解或封装POJO,Map方式适用于动态、不固定的参数,但可读性和安... 目录✅ android方式一:使用Map<String, Object>✅ 方式二:使用@Param

SpringBoot实现图形验证码的示例代码

《SpringBoot实现图形验证码的示例代码》验证码的实现方式有很多,可以由前端实现,也可以由后端进行实现,也有很多的插件和工具包可以使用,在这里,我们使用Hutool提供的小工具实现,本文介绍Sp... 目录项目创建前端代码实现约定前后端交互接口需求分析接口定义Hutool工具实现服务器端代码引入依赖获