代码随想录算法训练营第二十七天 | 39. 组合总和、40.组合总和II、131.分割回文串

39. 组合总和

题目链接:https://leetcode.cn/problems/combination-sum/
文档讲解:https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html
视频讲解:https://www.bilibili.com/video/BV1KT4y1M7HJ

思路

  • 这道题和之前做过的组合区别在于每个数都可以重复使用,在代码中体现为,递归时startIndex的值不用+1。
  • 剪枝优化:先将数组从小到大排序。在递归前判断,如果 sum+candidates[i] > target,就没必要再递归。

代码

未剪枝

class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> combinationSum(int[] candidates, int target) {backtracking(candidates, target, 0, 0);return res;}public void backtracking(int[] candidates, int target, int sum, int startIndex) {if (sum == target) {res.add(new ArrayList<>(path));return;}    if (sum > target) return; for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) {path.add(candidates[i]);backtracking(candidates, target, sum + candidates[i], i); // 不用i+1,因为当前节点可以重复被使用path.removeLast();}    }
}

剪枝优化

class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> combinationSum(int[] candidates, int target) {Arrays.sort(candidates); // 先进行排序backtracking(candidates, target, 0, 0);return res;}public void backtracking(int[] candidates, int target, int sum, int startIndex) {if (sum == target) {res.add(new ArrayList<>(path));return;}    if (sum > target) return;for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) { // 剪枝path.add(candidates[i]);backtracking(candidates, target, sum + candidates[i], i); // 不用i+1,因为当前节点可以重复被使用path.removeLast();}    }
}

40.组合总和II

题目链接:https://leetcode.cn/problems/combination-sum-ii/
文档讲解:https://programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html
视频讲解:https://www.bilibili.com/video/BV12V4y1V73A

思路

  • 这道题和前面的组合总和的区别在于数组中有重复元素,而结果中要求没有重复数组。这就需要对树的每一层的数进行去重,同层的数不能相等。因为要判断相邻元素是否相等,所以要先排序。
  • 去重方法一(我的思路):不使用标记数组。递归后判断当前数和数组中下一个数是否相等,如果相等就i++,跳过下一个元素。因为可能有多个重复的数,所以这里的判断用while而不是if
for (int i = startIndex; i < candidates.length; i++) {path.add(candidates[i]);backtracking(candidates, target, sum + candidates[i], i + 1);while (i + 1 < candidates.length && candidates[i] == candidates[i + 1]) i++; // 去重path.removeLast()
}

也可以和前一个数比较大小:

for (int i = startIndex; i < candidates.length; i++) {if ( i > start && candidates[i] == candidates[i - 1] ) continue; // 去重path.add(candidates[i]);backtracking(candidates, target, sum + candidates[i], i + 1);path.removeLast();
}
  • 去重方法二(卡哥的思路):使用标记数组。当前数和前一个数相等,并且前一个数的used为false,就需要去重。used之所以是false,说明两个数是同层的。如果uesd为true,说明被使用过,那上一个数就应该是上一层的数,而不是同层的数。
if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) { // 去重continue;
}

代码

去重方法一

class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> combinationSum2(int[] candidates, int target) {Arrays.sort(candidates);backtracking(candidates, target, 0, 0);return res;}public void backtracking(int[] candidates, int target, int sum, int startIndex) {if (sum == target) {res.add(new ArrayList<>(path));return;}if (sum > target) return;for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) { // 剪枝path.add(candidates[i]);backtracking(candidates, target, sum + candidates[i], i + 1);while (i + 1 < candidates.length && candidates[i] == candidates[i + 1]) i++; // 去重path.removeLast();}}
}

去重方法二

class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();boolean[] used;public List<List<Integer>> combinationSum2(int[] candidates, int target) {Arrays.sort(candidates);used = new boolean[candidates.length];Arrays.fill(used, false);backtracking(candidates, target, 0, 0);return res;}public void backtracking(int[] candidates, int target, int sum, int startIndex) {if (sum == target) {res.add(new ArrayList<>(path));return;}if (sum > target) return;for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) {if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) { // 去重continue;}path.add(candidates[i]);used[i] = true;backtracking(candidates, target, sum + candidates[i], i + 1);used[i] = false;path.removeLast();}}
}

131.分割回文串

题目链接:https://leetcode.cn/problems/palindrome-partitioning/
文档讲解: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

思路

  • 切割问题可以抽象为组合问题,每次选取的是切割的点,然后得到中间的一段字符串。所以我们只需要移动确定切割的起点和终点,然后截取他们中间的字符串。
  • 切割问题中递归的终止条件:当startIndex==s.length(),说明已经按照某种方案遍历完字符串,那么就可以提交一组切割方案了。
  • 判断回文串的方法:双指针法,从两端向中间靠拢。

代码

class Solution {List<List<String>> res = new ArrayList<>();List<String> path = new ArrayList<>();public List<List<String>> partition(String s) {backtracking(s, 0);return res;}public void backtracking(String s, int startIndex) {// startIndex控制的是起始位置,如果起始位置已经大于s的大小,说明已经找到了一组分割方案了if (startIndex >= s.length()) {res.add(new ArrayList<>(path));return;}for (int i = startIndex; i < s.length(); i++) {if (isPalindrome(s.substring(startIndex, i + 1))) {path.add(s.substring(startIndex, i + 1));backtracking(s, i + 1);path.removeLast();}}}public boolean isPalindrome(String s) {int left = 0, right = s.length() - 1;while (left < right) {if (s.charAt(left) != s.charAt(right)) return false;left++;right--;}return true;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/21751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何通过拟合平面找到lidar点云数据intensity导数

source: chatgpt 我是知识的搬运工&#xff0c;尝试弄懂chat老师给我写的代码&#xff0c;我的思考历程是这样的 我跟它说生成一个关于intensity的导数&#xff0c;这是它生成的结果&#xff1a; def compute_gradient(neighbors_pts, neighbors_int):Fit a plane I(x, y, z)…

基于java的CRM客户关系管理系统(六)

目录 5.3 表现层设计 5.3.1 模型层&#xff08;M&#xff09; 5.3.2 视图层&#xff08;V&#xff09; 5.3.3 控制层&#xff08;C&#xff09; 5.4 系统主要功能模块的实现 5.4.1 登录功能的实现 5.4.2 客户管理的实现 5.5 本章小结 参考文献 前面内容请移步 基于java…

【CSS】scroll-snap属性详解

目录 scroll-snap-type方向&#xff1a;捕捉强度&#xff1a; scroll-snap-stopscroll-paddingscroll-margin实际使用示例 scroll-snap 是一个用于实现流畅滚动捕捉效果的 CSS 模块。它包含多个属性&#xff0c;可以应用于滚动容器和滚动子项上。 scroll-snap-type scroll-sna…

k8s学习--Secret详细解释与应用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Secret什么是Secret?Secret四种类型及其特点Secret应用案例&#xff08;1&#xff09;将明文密码进行base64编码&#xff08;2&#xff09;编写创建secret的YAML文…

笔试训练2

牛客.单词搜索 刚开始我就想是搜索&#xff0c;但是不清楚bfs还是dfs更好&#xff0c;我尝试了bfs但是队列存东西&#xff0c;没有我想象的那么好写&#xff0c;所以我决定试试dfs import java.util.*;public class Solution {static int m 0;static int n 0;static int […

【Qt快速入门(一)】- Qt简介

目录 Qt快速入门&#xff08;一&#xff09;Qt简介历史背景跨平台特性核心组件开发工具Qt Creatorqmake和CMake Qt的主要应用领域桌面应用移动应用嵌入式系统游戏开发Web应用 Qt社区和生态系统Qt MarketplaceQt认证 未来发展 Qt快速入门&#xff08;一&#xff09; Qt简介 Qt…

【人工智能Ⅱ】实验8:生成对抗网络

实验8&#xff1a;生成对抗网络 一&#xff1a;实验目的 1&#xff1a;理解生成对抗网络的基本原理。 2&#xff1a;学会构建改进的生成对抗网络&#xff0c;如DCGAN、WGAN、WGAN-GP等。 3&#xff1a;学习在更为真实的数据集上应用生成对抗网络的方法。 二&#xff1a;实验…

SaaS销售新指标|一文带你读懂什么是反向拒付指标

saas企业销售也需要一系列的指标来衡量企业运营情况如何&#xff1f;有哪些值得改善的地方&#xff1f;今天林叔发现一个比较有意思的新指标&#xff1a;反向拒付。希望能帮助saas企业更好的运营。 一、什么是反向拒付&#xff1f; **反向拒付指标&#xff08;反拒付指标&…

C基础-标准库下

上:http://t.csdnimg.cn/qj5uA 目录 七. math.h 八. setjmp.h 九. signal.h 十. stdarg.h 十一.stddef.h 十二. stdio.h 十三. stdlib. 十四. string.h 十五. time.h 七. math.h 定义了各种数学函数和一个宏。 宏和函数描述 序号宏 & 描述1HUGE_VAL 当函数的结…

Vue3——实现word,pdf上传之后,预览功能(实测有效)

vue-office/pdf - npm支持多种文件(**docx、excel、pdf**)预览的vue组件库&#xff0c;支持vue2/3。也支持非Vue框架的预览。. Latest version: 2.0.2, last published: a month ago. Start using vue-office/pdf in your project by running npm i vue-office/pdf. There are …

怎么样的电销机器人才是好的?智能语音机器人部署

在现代社会&#xff0c;营销策略对于企业的成功至关重要。随着技术的发展&#xff0c;电销机器人正在改变传统营销模式&#xff0c;取而代之的是更高效&#xff0c;更自动化和更个性化的方式。 当然&#xff0c;如何选择合适的电销机器人是很重要的。所以&#xff0c;我们就来看…

Mybatis实现树形结构方式

1&#xff0c;三级分类树形结构查询 /*** DDD(Domain-Driven Design): 领域驱动设计** 三级分类树形结构&#xff1b;* 支持无限层级&#xff1b;* 当前项目只有三级*/ Data public class CategoryTreeTo {private Long categoryId; //1private String categoryName;private …

ENVI 5.3/6.0打开Landsat 8/9 C2L2级别数据(带有Metadata),附常见问题

ENVI 5.3/6.0打开Landsat 8/9 C2L2级别数据&#xff08;带有Metadata&#xff09; 文章目录 ENVI 5.3/6.0打开Landsat 8/9 C2L2级别数据&#xff08;带有Metadata&#xff09;前言数据下载ENVI 5.3打开Landsat 8 C2L2级别数据ENVI 5.3打开Landsat 9 C2L2级别数据ENVI 6.0打开La…

RDMA介绍

RDMA全称是Remote Direct Memory Access&#xff0c;即远程直接内存访问&#xff0c;是一种高性能网络通信技术&#xff0c;可以使计算机直接访问远端计算机的内存&#xff0c;而无需在本地和远程计算机之间进行数据复制。 相比于传统的网络通信方式&#xff0c;RDMA技术具有更…

手写防抖debounce

手写防抖debounce 应用场景 当需要在事件频繁触发时&#xff0c;只执行最后一次操作&#xff0c;可以使用防抖函数来控制函数的执行频率,比如窗口resize事件和输入框input事件&#xff1b; 这段代码定义了一个名为 debounce 的函数&#xff0c;它接收两个参数&#xff1a;fn…

颠覆传统:探索Web3对传统计算机模式的冲击

随着Web3技术的崛起&#xff0c;传统计算机模式正面临着前所未有的冲击与挑战。Web3作为下一代互联网的代表&#xff0c;以其去中心化、安全可信的特性&#xff0c;正在颠覆着传统计算机模式的种种假设和局限性。本文将深入探讨Web3对传统计算机模式的冲击&#xff0c;并探索其…

关于stm32的复用和重映射问题

目录 需求IO口的复用和重映射使用复用复用加重映射 总结参考资料 需求 一开始使用stm32c8t6&#xff0c;想实现pwm输出&#xff0c;但是原电路固定在芯片的引脚PB10和PB11上&#xff0c;查看了下引脚的功能&#xff0c;需要使用到复用功能。让改引脚作为定时器PWM的输出IO口。…

PMP应考小技巧有哪些?

首先&#xff0c;制定合理的学习计划。将备考过程分解为小目标&#xff0c;并为每个目标设定截止日期。这样可以帮助我们有条不紊地进行学习&#xff0c;避免拖延和压力过大。 其次&#xff0c;选择适合自己的学习资源。PMP考试教材众多&#xff0c;可以选择一本权威的教材作为…

Idea-Linux远程开发部署

第一步&#xff1a;File->Remote Development 第二步&#xff1a; 第三步&#xff1a; 第四步&#xff1a;在Host位置填写Linux虚拟机的IP地址&#xff0c;在Username、Password填写对应的账号密码后点击Test Connection测试连接。 第五步&#xff1a; 第六步&#xff1a;在…

项目:仿RabbitMQ实现的消息队列组件

文章目录 写在前面开源仓库和项目上线其他文档说明 需求分析BrokerServer交换机类型持久化消息应答 模块划分服务端模块客户端模块交换机数据管理模块队列数据管理模块绑定数据管理模块消息数据管理模块队列信息管理模块虚拟机数据管理模块路由匹配模块消费者管理模块信道管理模…