网站建设营销话术,dedecms怎么关闭网站,做淘宝网站的编程实例,Pdf书籍网站建设语言#xff1a;Java/Go
39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target #xff0c;找出 candidates 中可以使数字和为目标数 target 的所有不同组合 #xff0c;并以列表形式返回。你可以按任意顺序返回这些组合。 candidates 中的同一个…语言Java/Go
39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target 找出 candidates 中可以使数字和为目标数 target 的所有不同组合 并以列表形式返回。你可以按任意顺序返回这些组合。 candidates 中的同一个数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同则两种组合是不同的。 对于给定的输入保证和为 target 的不同组合数少于 150 个。 示例 1 输入candidates [2,3,6,7],
target 7输出[[2,2,3],[7]]
解释2 和 3 可以形成一组候选2 2 3 7 。注意 2 可以使用多次。7 也是一个候选 7 7 。仅有这两种组合。 提示 1 candidates.length 302 candidates[i] 40candidates 的所有元素 互不相同1 target 40 本题的一大特点是没有组合数量的要求可以无限重复但是有总和的限制所以间接的也是有个数的限制。这里的剪枝操作就是如果当前的sum已经大于target。
class Solution {ListListInteger res new ArrayList();LinkedListInteger path new LinkedList();public void backTracking(int[] candidates, int target, int sum, int startIdx){if(sum target){res.add(new ArrayList(path));return;}if(sum target) return;for(int i startIdx; i candidates.length; i){sum candidates[i];path.add(candidates[i]);if (sum target) {backTracking(candidates, target, sum, i); //注意这里传递的是 i而不是i1为了可以重复取值}sum - candidates[i];path.removeLast();}}public ListListInteger combinationSum(int[] candidates, int target) {backTracking(candidates, target, 0, 0);return res;}
}组合没有数量要求元素可无限重复选取
组合总结
1. 什么时候需要startIdx如果是一个集合来求组合就需要如果是多个集合取组合就不需要。
2. 什么时候在调用递归backTracking ()的时候1如果不可以重复则需要1否则不用1
40.组合总和II 给定一个候选人编号的集合 candidates 和一个目标数 target 找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意解集不能包含重复的组合。 示例 1:输入: candidates [10,1,2,7,6,1,5], target 8,所求解集为: [[1, 7],[1, 2, 5],[2, 6],[1, 1, 6]
]示例 2:输入: candidates [2,5,2,1,2], target 5,所求解集为: [[1,2,2],[5]
] 本题和上一题的区别在于
本题candidates中的每个数字在每个组合中只能使用一次。本题数组candidates的元素是有重复的而上一题是无重复元素的数组candidates
关于使用一次这个问题的理解组合问题可以抽象为树形结构那么“使用过”在这个树形结构上是有两个维度的一个维度是同一树枝上使用过一个维度是同一树层上使用过。示例中给出的组合在同一个组合中可以有重复但是不能有重复的组合。
同一树枝上的都是一个组合里的元素不用去重。同一树层上的是不同的组合所以不可以重复。具体来讲假如数组为[1,1,2,7]那么如果第一个1取完以后继续从剩下的两个元素中取值会出现[1,1],[1,2],[1,7]这个操作是可以的因为前两个1只是数值相同但并不是同一个元素但是如果第一次取的是第二个1那么其实后面的取值过程会和取第一个1的时候重复这就造成了树层的重复。所以去重的方法就是将当前的candidates数组排序以后如果candidates[i]candidates[i-1] 就跳过当前循环继续寻找下一个数。
其实可以不借助新的数组用startIdx进行去重也可以。
import java.util.Arrays;
class Solution {ListListInteger resnew ArrayList();LinkedListInteger path new LinkedList();public void backTracking(int[] candidates, int target, int sum, int startIdx){if(sumtarget) return;if(sum target){res.add(new ArrayList(path));}for(int istartIdx;icandidates.length;i){// 要对同一树层使用过的元素进行跳过if(istartIdx candidates[i]candidates[i-1]){continue;}sumcandidates[i];path.add(candidates[i]);if(sumtarget){backTracking(candidates, target, sum,i1);}sum-candidates[i];path.removeLast();}}public ListListInteger combinationSum2(int[] candidates, int target) {Arrays.sort(candidates);backTracking(candidates, target, 0,0);return res;}
}
131.分割回文串 给你一个字符串 s请你将 s 分割成一些子串使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 示例: 输入: aab 输出: [ [aa,b], [a,a,b] ] 这道题需要解决两个问题1如何切割2怎么判断是否为回文串
切割问题其实类似于组合问题也可以抽象为一个树结构
这里切割过的地方不能重复切割和组合问题也是保持一致的所以也需要startIdx。
从图中可以看到切割线切到了字符串最后面说明找到了一种切割方法此时就是本层递归的终止条件。每次切割是从startIdx开始的所以startIdx即为切割线。当startIdxs.length()时切割终止。
每切割一次就要判断剩下的子串是否为回文串如果是回文串就将其加入path中。如果不是就跳过。
可以用双指针法判断是否为回文串设置start和end指针如果前后指针所指向的元素相等直到startend那么就是回文串。
class Solution {ListListString resnew ArrayList();LinkedListString path new LinkedList();public boolean isPalindrome(String s, int start, int end){for(int istart, jend;ij;i,j--){if(s.charAt(i)!s.charAt(j)){return false;}}return true;}public void backTracking(String s, int startIdx){if(startIdxs.length()){res.add(new ArrayList(path));}for(int istartIdx;is.length();i){if(isPalindrome(s, startIdx, i)){String strs.substring(startIdx, i1);path.add(str);}else{continue;}backTracking(s, i1); //确保不重复path.removeLast();}}public ListListString partition(String s) {backTracking(s,0);return res;}
}
本题难点和思路如下
切割问题可以抽象为组合问题如何模拟那些切割线切割问题中递归如何终止在递归循环中如何截取子串如何判断回文