代码随想录day23 | leetcode 39.组合总和 40.组合总和II

news2024/12/22 1:57:15

39.组合总和

Java

class Solution {     
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        backtracking(candidates,target,0,0);
        return result;
    }
    public void backtracking(int[] candidates,int target,int sum,int startIndex){
        if (sum>target){
            return;
        }
        if (sum == target){
            result.add(new LinkedList<>(path));
            return;
        }
        for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) {
            path.add(candidates[i]);
            sum += candidates[i];
            backtracking(candidates,target,sum,i);
            sum -= candidates[i];
            path.removeLast();
          
        }
    }
}
回溯方法:backtracking
public void backtracking(int[] candidates, int target, int sum, int startIndex) {
    if (sum > target) { // 剪枝:如果当前和已经超过目标,直接返回
        return;
    }
    if (sum == target) { // 找到满足条件的组合
        result.add(new LinkedList<>(path)); // 保存当前路径到结果
        return;
    }
    for (int i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) {
        path.add(candidates[i]); // 做选择:将当前数字加入路径
        sum += candidates[i]; // 更新路径总和
        backtracking(candidates, target, sum, i); // 递归,允许重复选择当前数字
        sum -= candidates[i]; // 撤销选择:恢复之前的状态
        path.removeLast(); // 从路径中移除最后一个数字,回溯
    }
}
逻辑解释
  1. 递归终止条件
    • sum > target:当前路径总和超过目标值,停止递归。
    • sum == target:找到一组符合条件的组合,将 path 复制加入结果。
  2. 循环递归
    • 循环起点:从 startIndex 开始,保证每次递归处理当前数字及其后续数字。
    • 条件:sum + candidates[i] <= target- 剪枝条件,提前终止无意义的递归。
    • 允许重复选择:- 递归调用时仍从 i 开始 (backtracking(candidates, target, sum, i)),因此当前数字可以重复加入组合。
  3. 回溯过程
    • path.add(candidates[i])path.removeLast():分别表示“选择当前数字”和“撤销选择”。
    • sum += candidates[i]sum -= candidates[i]:动态更新当前路径的总和。

40.组合总和II

树层去重一个数完整搜完一边,另一个重复的数不用搜第二遍

Java

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

关键点

  1. 数组排序
	Arrays.sort(candidates);

对数组 candidates 进行排序是为了方便去重和剪枝。排序后,相同的元素会相邻,可以通过简单的逻辑避免重复。

  1. 去重逻辑
	if (i > 0 && candidates[i - 1] == candidates[i] && used[i - 1] == false) {
	    continue;
	}

这一部分用于按“层”去重。如果当前元素与前一个元素相同,且前一个元素在当前层没有被使用(used[i - 1] == false),就跳过这个元素,避免重复组合。

  1. 递归与回溯
    • 递归条件:递归深入到下一层(选择下一个数字)。
    • 回溯操作:撤销上一步的选择(移除当前路径中的数字,恢复 sumused 的状态)。

代码逻辑

全局变量
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
  • result:存储最终的所有满足条件的组合。
  • path:存储当前递归路径上的数字组合。

主函数
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    Arrays.sort(candidates); // 排序,方便去重和剪枝
    boolean[] used = new boolean[candidates.length]; // 记录每个数字是否使用
    backtracking(candidates, target, 0, 0, used); // 初始状态
    return result;
}
  • 对数组排序后,初始化 used 数组为 false
  • 调用回溯函数 backtracking 开始寻找组合。

回溯函数
public void backtracking(int[] candidates, int target, int sum, int stateIndex, boolean[] used) {
    if (sum > target) {
        return; // 剪枝:当前组合和大于目标值
    }
    if (sum == target) {
        result.add(new ArrayList<>(path)); // 找到符合条件的组合,加入结果集
        return;
    }
    for (int i = stateIndex; i < candidates.length; i++) {
        if (i > 0 && candidates[i - 1] == candidates[i] && used[i - 1] == false) {
            continue; // 去重:跳过相同的元素
        }
        path.add(candidates[i]); // 添加当前数字到路径
        sum += candidates[i]; // 更新路径和
        used[i] = true; // 标记当前数字为已使用
        backtracking(candidates, target, sum, i + 1, used); // 递归到下一层
        path.removeLast(); // 回溯,撤销选择
        sum -= candidates[i]; // 恢复路径和
        used[i] = false; // 恢复使用状态
    }
}

重点逻辑

  1. 递归结束条件
    • sum > target 时,直接返回,表示当前路径无效。
    • sum == target 时,说明找到一个符合条件的组合,将其加入 result
  2. 去重
	if (i > 0 && candidates[i - 1] == candidates[i] && used[i - 1] == false) {
	    continue;
}

按“层”去重。只有当前层的数字和前一个数字相同时,才需要检查是否跳过。
3. 递归与回溯
- 递归:将当前数字加入路径后,继续递归处理下一层。
- 回溯:撤销选择,包括移除路径中的数字,恢复 sumused 的状态。

131.分割回文串

Java

class Solution {
       List<List<String>> result = new ArrayList<>();
    LinkedList<String> path = new LinkedList<>();
    public List<List<String>> partition(String s) {
         backtracking(s,0);
        return result;
    }

        public void backtracking(String s,int startIndex){
        if (startIndex >= s.length()){
            result.add(new ArrayList<>(path));
            return;
        }

        for (int i = startIndex; i < s.length(); i++) {
            if (isPalindrome(s,startIndex,i)){
                String a = s.substring(startIndex,i+1);
                path.add(a);
            }
            else {
                continue;
            }
            backtracking(s,i+1);
            path.removeLast();
        }



    }

        boolean isPalindrome(String s,int start,int end){
        for (int i = start,j = end; i <j ; i++,j--) {
            if (s.charAt(i)!=s.charAt(j)){
                return false;
            }
        }
        return true;
    }
}
全局变量
List<List<String>> result = new ArrayList<>();
LinkedList<String> path = new LinkedList<>();
  • result:存储所有满足条件的分割方案。
  • path:当前递归路径,表示当前的分割方案。

主函数
public List<List<String>> partition(String s) {
    backtracking(s, 0); // 从索引 0 开始划分字符串
    return result;
}
  • 调用回溯函数 backtracking 从字符串的第一个字符开始分割。
  • 返回所有满足条件的方案。

回溯函数
public void backtracking(String s, int startIndex) {
    if (startIndex >= s.length()) {
        result.add(new ArrayList<>(path)); // 如果遍历到字符串末尾,记录当前路径
        return;
    }

    for (int i = startIndex; i < s.length(); i++) {
        if (isPalindrome(s, startIndex, i)) { // 判断从 startIndex 到 i 的子串是否是回文
            String a = s.substring(startIndex, i + 1); // 取出当前回文子串
            path.add(a); // 加入路径
        } else {
            continue; // 如果不是回文,跳过本次循环
        }
        backtracking(s, i + 1); // 递归处理剩下的部分
        path.removeLast(); // 回溯,移除最后一个子串
    }
}
  • 终止条件:- 当 startIndex 超过或等于字符串长度时,说明已经分割完毕,记录当前路径。
  • 递归逻辑:- 从 startIndex 开始,尝试分割到每个可能的位置 i
    • 如果 s[startIndex...i] 是回文,则加入路径,并递归处理 s[i+1...end]
    • 递归返回后,回溯移除当前子串。

判断是否为回文
boolean isPalindrome(String s, int start, int end) {
    for (int i = start, j = end; i < j; i++, j--) {
        if (s.charAt(i) != s.charAt(j)) {
            return false; // 如果两端字符不相等,不是回文
        }
    }
    return true; // 如果所有字符都相等,是回文
}
  • 双指针法,检查从 startend 的子串是否为回文。
  • 左右两端字符逐步比较,如果有任意一对不相等,则不是回文。

算法流程

  1. 从字符串 s 的第一个字符开始,尝试划分每个可能的回文子串。
  2. 如果找到一个回文子串,加入当前路径,并继续递归处理剩余部分。
  3. 当划分到字符串末尾时,将当前路径记录为一种有效方案。
  4. 回溯时移除最后一个子串,尝试其他划分方式。

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

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

相关文章

Unity3D仿星露谷物语开发5之角色单例模式

1、目的 使用单例模式创建角色对象&#xff0c;保证整个游戏中只有一个角色&#xff0c;并且让游戏对象具有全局可访问性。 2、流程 &#xff08;1&#xff09;创建SingletonMonobehaviour脚本 Assets下创建Scripts目录用于存放所有的脚本&#xff0c;再创建Misk子目录&…

控制表格向上滚动距离最佳实践(以Element ui为例)

前言 在web开发中&#xff0c;有些时候使用的组件库的表格不支持滚动的属性或方法。这个时候我们就要自己去实现这一功能。在Element Plus里&#xff0c;组件库已经具备了支持滚动表格的属性或方法&#xff0c;但是在支持vue2的element ui里&#xff0c;Table组件本身不提供直…

ubuntu16.04ros-用海龟机器人仿真循线系统

下载安装sudo apt-get install ros-kinetic-turtlebot ros-kinetic-turtlebot-apps ros-kinetic-turtlebot-interactions ros-kinetic-turtlebot-simulator ros-kinetic-kobuki-ftdi sudo apt-get install ros-kinetic-rocon-*echo "source /opt/ros/kinetic/setup.bash…

6.3 Postman环境变量与全局变量

欢迎大家订阅【软件测试】 专栏&#xff0c;开启你的软件测试学习之旅&#xff01; 文章目录 前言1 变量类型2 环境变量&#xff08;Environment Variables&#xff09;3 全局变量&#xff08;Global Variables&#xff09;4 环境变量与全局变量的区别 前言 为了提高测试的灵活…

概率论得学习和整理27:关于离散的数组 随机变量数组的均值,方差的求法3种公式,思考和细节。

目录 1 例子1&#xff1a;最典型的&#xff0c;最简单的数组的均值&#xff0c;方差的求法 2 例子1的问题&#xff1a;例子1只是1个特例&#xff0c;而不是普遍情况。 2.1 例子1各种默认假设&#xff0c;导致了求均值和方差的特殊性&#xff0c;特别简单。 2.2 我觉得 加权…

模型 QFD(质量功能展开/质量屋)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。将客户需求转化为产品设计。 1 模型 QFD&#xff08;质量功能展开&#xff09;的应用 1.1 电信服务及网络维护过程质量改进QFD应用案例 背景介绍&#xff1a; 随着中国加入WTO和国家对电信管制的普遍…

ECharts柱状图-柱图38,附视频讲解与代码下载

引言&#xff1a; 在数据可视化的世界里&#xff0c;ECharts凭借其丰富的图表类型和强大的配置能力&#xff0c;成为了众多开发者的首选。今天&#xff0c;我将带大家一起实现一个柱状图图表&#xff0c;通过该图表我们可以直观地展示和分析数据。此外&#xff0c;我还将提供…

Android XR 应用程序开发 | 从 Unity 6 开发准备到应用程序构建的步骤

在本文中 将解释为 Android XR 开发做准备的步骤&#xff0c;从下载 Unity 6 到项目和构建。 &#xff08;这次我将解释使用 Mac 的设置&#xff0c;但 Windows 的过程通常相同。 &#xff09; 如果您的许可证是 Personal&#xff0c;您仍然可以使用 Unity 开发 Android XR 应…

204页PPT金税四期监管要求与最新政策及风险防范-培训课件

这份资料是关于金税四期监管要求、最新政策及风险防范的培训课件&#xff0c;包含204页PPT内容。核心内容涉及金税四期的发展历程、与金税三期的主要变化、指挥决策系统、税务风险预警指标、重点监控行为、税务稽查重点领域、避税方法及处罚、以及企业自查和税务风险管控原理。…

比较器基本玩法

1 红外水龙头 1 比较器的工作特性 2 红外接收二极管的工作原理 1 红外发射二极管和红外接收二极管 2 红外接收二极管接收到&#xff0c;产生的电流是100uA&#xff0c;即电压等于4V 3 自动出水水龙头 4 比较器内部结构 1 有一些比较器需要加上拉电阻&#xff08;类似开漏输…

基于Qt的登陆界面设计

目标 自由发挥登录界面的应用场景&#xff0c;实现一个登录窗口的界面。 要求&#xff1a;每行代码都要有注释 代码 // 设置窗口大小为600x400像素 this->resize(600,400); // 设置窗口标题为"TheWitcher 巫师3&#xff1a;狂猎" this->setWindowTitle(&qu…

数据库建模工具 PDManer

数据库建模工具 PDManer 1.PDManer简介2.PDManer使用 1.PDManer简介 PDManer&#xff08;元数建模&#xff09;是一款功能强大且易于使用的开源数据库建模工具。它不仅支持多种常见数据库&#xff0c;如MySQL、PostgreSQL、Oracle、SQL Server等&#xff0c;还特别支持国产数据…

排序算法深度好文(图解 + 代码解析 + 误区 QA )——学排序看这一篇就够了!!!

排序算法 一、概述 1. 内部排序 (1) 冒泡排序 (2) 选择排序 a. 简单选择排序 b. 堆排序 (3) 插入排序 a. 直接插入排序 b. 希尔排序 (4) 快速排序 快速排序 hoare 版本 快速排序挖坑法 优化一随机化快速排序 优化二中位数三分法 (5) 归并排序 (6) 基数排序 2. …

【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】

目录&#x1f60b; <第1关&#xff1a;顺序结构的应用> 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果&#xff1a; <第2关&#xff1a;交换变量值> 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果&#xff1a; <第…

git stash 的文件如何找回

在Git中&#xff0c;如果你使用了git stash命令来保存你的工作进度&#xff0c;但之后想要找回这些被stash的文件&#xff0c;你可以按照以下步骤进行操作&#xff1a; 1. 查看stash列表 首先&#xff0c;使用git stash list命令来查看当前保存的所有stash记录。这个命令会列出…

【报表查询】.NET开源ORM框架 SqlSugar 系列

文章目录 前言实践一、按月统计没有为0实践二、 统计某月每天的数量实践三、对象和表随意JOIN实践四、 List<int>和表随意JOIN实践五、大数据处理实践六、每10分钟统计Count实践七、 每个ID都要对应时间总结 前言 在我们实际开发场景中&#xff0c;报表是最常见的功能&a…

基于asp.net游乐园管理系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…

电脑上怎么运行手机APP(电脑上运行手机APP的4种方法)

玩家可能不愿意在小屏幕上使用 Android 应用程序。此外&#xff0c;某些游戏玩家可能更喜欢在更大的屏幕上寻找刺激的体验&#xff0c;例如 PC 提供的体验&#xff0c;这可以增强他们的乐趣。因此&#xff0c;他们可能对如何在 PC 上流畅地运行 Android 应用程序感到好奇。本指…

oscp学习之路,Kioptix Level1靶场小白速通教程

oscp学习之路&#xff0c;Kioptix Level1靶场小白速通教程 有意向学习oscp的可以私信我一起交流学习 1.前期准备 首先下载好靶场文件&#xff0c;通过nmap进行扫描&#xff0c;确定IP地址和开放端口 发现IP是192.168.201.129,开放的端口为22,80,111,139,443,1024这几个端口。访…

【Ubuntu】设置静态Ip

查看网卡 ifconfig | grep -A 5 -B 2 192 修改配置文件 sudo vim /etc/netplan/00-installer-config.yamlnetwork:ethernets:enp0s3:dhcp4: noaddresses:- 192.168.1.100/24gateway4: 192.168.1.1nameservers:addresses:- 8.8.8.8- 8.8.4.4​​​​​