算法训练Day27|39. 组合总和● 40.组合总和II● 131.分割回文串

简介: 算法训练Day27|39. 组合总和● 40.组合总和II● 131.分割回文串

LeetCode:39. 组合总和

39. 组合总和 - 力扣(LeetCode)

1.思路

嵌套for循环,层数未知,用递归实现。

先对数组排序,方便后面剪枝操作,优化搜索,

确定单层递归的逻辑backtracking(),传入结果集List> res, List path, int[] candidates, int target, int sum, int idx(防止递归调用重复的数字)

最后,对path调用remove(path.size() - 1) 回溯,查找后面复合条件的路径


2.代码实现

 1class Solution {
 2    public List<List<Integer>> combinationSum(int[] candidates, int target) {
 3        List<List<Integer>> res = new ArrayList<>(); // 存储结果的结果集
 4        Arrays.sort(candidates); // 对其进行排序,便于剪枝操作(优化搜索过程)
 5        backtracking(res, new ArrayList<>(), candidates, target, 0, 0); // 调用递归函数进行回溯搜索
 6        return res;
 7    }
 8
 9    public void backtracking(List<List<Integer>> res, List<Integer> path, int[] candidates, int target, int sum, int idx) {
10        // 如果当前路径的和等于目标值,将路径加入结果集并返回
11        if (sum == target) {
12            res.add(new ArrayList<>(path));
13            return;
14        }
15        // 遍历数组中的元素
16        for (int i = idx; i < candidates.length; i++) {
17            if (sum + candidates[i] > target) break; // 终止条件:如果当前和大于目标值,剪枝操作
18            path.add(candidates[i]);  // 不大于目标和,则将元素加入路径
19            backtracking(res, path, candidates, target, sum + candidates[i], i); // 递归调用下一个元素
20            path.remove(path.size() - 1); // 回溯,移除路径 path 最后一个元素,寻找新的路径
21        }
22    }
23}

3.复杂度分析

时间复杂度:时间消耗取决于for循环层数和递归函数调用次数,则为O(nm)n.

空间复杂度:取决于递归函数调用深度/层数,O(i).


LeetCode:40.组合总和II

40. 组合总和 II - 力扣(LeetCode)


1.思路

组合问题,元素有重复,但结果不允许重复,则需要考虑枝干层元素的去重。

设置used[]数组对元素是否重复进行标记,对数组元素进行排序,便于剪枝,优化搜索。

确定递归函数,剪枝操作(sum>target/树层去重),for循环遍历,添加,加和,标记,递归,最后回溯。


2.代码实现

 1class Solution {
 2    LinkedList<Integer> path = new LinkedList<>(); // 存储当前路径的链表
 3    List<List<Integer>> ans = new ArrayList<>(); // 存储所有符合结果的结果集
 4    boolean[] used; // 记录元素是否被使用过的数组
 5    int sum = 0; // 当前路径元素的和
 6
 7    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
 8        used = new boolean[candidates.length]; // 初始化used[]数组
 9        Arrays.fill(used,false); // 全部置为false
10        Arrays.sort(candidates); // 将数组candidates[] 排序,便于剪枝操作,优化搜索
11        backtracking(candidates, target, 0); // 调用递归函数进行递归搜索
12        return ans;
13    }
14
15    private void backtracking(int[] candidates, int target, int startIndex) {
16        // 将符合条件的结果加入到结果集中
17        if (sum == target) {
18            ans.add(new ArrayList(path));
19        }
20        // 横向遍历所有元素
21        for (int i = startIndex; i < candidates.length; i++) {
22            // 当前路径元素和大于目标target,剪枝操作
23            if (sum + candidates[i] > target) {
24                break;
25            }
26            // 当前节点大于0且遇到重复元素且上一个元素没有用过,则当前元素与后序存在重复,剪枝操作
27            if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {
28                continue;
29            }
30            // 符合加入路径条件的
31            used[i] = true; // 记录该元素使用过
32            sum += candidates[i]; // sum加上当前元素
33            path.add(candidates[i]); // 将元素值加入路径
34            // 每个节点仅能选择一次,所以从下一位开始 i + 1
35            // 竖向递归选出符合条件的元素
36            backtracking(candidates, target, i + 1);
37            // 回溯——修改used值——和减去最后一个值——路径减去最后一个元素
38            used[i] = false;
39            sum -=candidates[i];
40            path.removeLast();
41        }
42    }
43}

3.复杂度分析

时间复杂度:O(2^n)*n.

空间复杂度:O(n).


LeetCode:131.分割回文串

131. 分割回文串 - 力扣(LeetCode)


1.思路

和组合类似的思路,多了个回文子串的判断。

for循环进行横向遍历切割,判断每段字符串为回文子串并输出结果。


2.代码实现

 1class Solution {
 2    List<List<String>> lists = new ArrayList<>(); // 存放结果的结果集
 3    Deque<String> deque = new LinkedList<>(); // 用于存放回文子串的队列
 4
 5    public List<List<String>> partition(String s) {
 6        backtracking(s, 0); // 调用回溯函数进行搜索
 7        return lists; // 返回结果集
 8    }
 9    private void backtracking(String s, int startIndex) {
10        // 遍历到最后位置,startIndex在这里更像是索引
11        if (startIndex >= s.length()) {
12            lists.add(new ArrayList(deque)); // 将结果加入结果集中
13            return;
14        }
15        // 横向遍历字符串
16        for (int i = startIndex; i < s.length(); i++) {
17            // 判断是否是回文字符串
18            if (isPalindrome(s, startIndex, i)) {
19                // 如果是回文串,将其加入到队列中
20                String str = s.substring(startIndex, i + 1);
21                deque.addLast(str);
22            } else {
23                // 不是,则结束本次循环,继续下一次循环
24                continue;
25            }
26            // 递归调用函数,继续搜索下一个回文子串
27            backtracking(s, i + 1);
28            deque.removeLast(); // 回溯 删除队列中最后一个元素,便于加入其他可能的回文子串
29        }
30    }
31    // 判断字符串是否是回文子串
32    private boolean isPalindrome(String s, int startIndex, int end) {
33        // 双指针+for循环遍历
34        for (int i = startIndex, j = end; i < j; i++, j--) {
35            if (s.charAt(i) != s.charAt(j)) {
36                return false;
37            }
38        }
39        return true;
40    }
41}

3.复杂度分析

时间复杂度:O(2^n)*n.

空间复杂度:O(n^2).每次for循环调用一个回溯函数一个回文子串函数.n个元素则调用n^2层的深度


相关文章
|
3月前
|
canal 算法 vr&ar
【图像处理】基于电磁学优化算法的多阈值分割算法研究(Matlab代码实现)
【图像处理】基于电磁学优化算法的多阈值分割算法研究(Matlab代码实现)
142 1
|
9月前
|
算法
一次推理,实现六大3D点云分割任务!华科发布大一统算法UniSeg3D,性能新SOTA
华中科技大学研究团队提出了一种名为UniSeg3D的创新算法,该算法通过一次推理即可完成六大3D点云分割任务(全景、语义、实例、交互式、指代和开放词汇分割),并基于Transformer架构实现任务间知识共享与互惠。实验表明,UniSeg3D在多个基准数据集上超越现有SOTA方法,为3D场景理解提供了全新统一框架。然而,模型较大可能限制实际部署。
747 15
|
存储 机器学习/深度学习 算法
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
蓝桥杯Python编程练习题的集合,涵盖了从基础到提高的多个算法题目及其解答。
701 3
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
机器学习/深度学习 算法 决策智能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
|
算法 Java C++
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
|
算法 C++
第一周算法设计与分析 E : 构造回文串
这篇文章介绍了解决算法问题"构造回文串"的方法,即判断给定的整数N(视为字符串)是否可以通过在前面添加任意个0(或不添加)来构造一个回文串,并给出了相应的C++代码实现。
|
算法 Java 索引
数据结构与算法学习十五:常用查找算法介绍,线性排序、二分查找(折半查找)算法、差值查找算法、斐波那契(黄金分割法)查找算法
四种常用的查找算法:顺序查找、二分查找(折半查找)、插值查找和斐波那契查找,并提供了Java语言的实现代码和测试结果。
267 0
|
算法 C++
蓝桥 算法训练 共线(C++)
蓝桥 算法训练 共线(C++)
knn增强数据训练
【7月更文挑战第28天】
231 2

热门文章

最新文章