LeetCode 131、分割回文数
这个题和昨天的最后一个题差不多是一样的,都是对某个字符串对其分割,因此需要一个start索引,对分割字符串的起点对其管理,还有就是这个题所要满足存入的条件是字符串为回文数,那么就是说,我们需要在循环中,先判断此时分割出来的字符串是不是一个回文,如果是的话再存入list。然后继续往下递归。
class Solution {
List<List<String>> res =new ArrayList<>();
public List<List<String>> partition(String s) {
if(s.equals("")){
return res;
}
ArrayList<String> lis = new ArrayList<>();
DFS(s,0,lis);
return res;
}
public void DFS(String s,int start,List<String> lis){
if (start==s.length()){
ArrayList<String> strings = new ArrayList<>();
strings.addAll(lis);
res.add(strings);
}else {
for (int i = start; i <s.length() ; i++) {
String str = s.substring(start, i+1);
int x=0;
int y=str.length()-1;
boolean falg =true;
while (x<=y){
if (str.charAt(x)!=str.charAt(y)) {
falg=false;
break;
}
x++;
y--;
}
if (falg){
lis.add(str);
DFS(s, i+1, lis);
lis.remove(lis.size()-1);
}
}
}
}
}
LeetCode 77、组合
此题唯一的限制就是要保证list的size为k,一次让其作为递归结束条件,
class Solution {
List<List<Integer>> res1 =new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
if(n<k||k<=0){
return res1;
}
ArrayList<Integer> list = new ArrayList<>();
combineNum(n, k, 1, list);
return res1;
}
public void combineNum(int n,int k,int start,List<Integer> list){
if (list.size()==k){
ArrayList<Integer> list1 = new ArrayList<>();
list1.addAll(list);
res1.add(list1);
return;
}else {
for (int i = start; i <=n-(k-list.size())+1 ; i++) {
list.add(i);
combineNum(n, k, i+1, list);
list.remove(list.size()-1);
}
}
}
}
39组合总和1
class Solution {
List<List<Integer>> res1 =new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates.equals("")||target<=0){
return res1;
}
ArrayList<Integer> list = new ArrayList<>();
combination(candidates,target,list,0);
return res1;
}
public void combination(int[] candidates,int target,List<Integer> list,int index){
if(target<=0){
if(target==0){
ArrayList<Integer> list1 = new ArrayList<>();
list1.addAll(list);
res1.add(list1);
}
return;
}else{
for(int i =index;i<candidates.length;i++){
list.add(candidates[i]);
combination(candidates,target-candidates[i],list,i);
list.remove(list.size()-1);
}
}
}
}
这个题就有些不同了。
特别之处在于所有的元素都可以重复取,当然我们还是能用相同的算法结构,需要思考的是遍历递归回溯部分。
我们发现,当一个数已经确定之后,在它的子分支中依旧还是能选择这个这个数,但是在它平行的分支中,就不能再选了,因此不需要在子分支中重新定位它的循环开始点,而是与父节点是相同的。
LeetCode 40、组合总和2
class Solution {
boolean[] falgs ;
List<List<Integer>> res1 =new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
falgs=new boolean[candidates.length];
if(candidates.equals("")||target<=0){
return res1;
}
Arrays.sort(candidates);
ArrayList<Integer> list = new ArrayList<>();
combination(candidates,target,list,0);
return res1;
}
public void combination(int[] candidates,int target,List<Integer> list,int index){
if(target<=0||index==candidates.length){
if(target==0){
ArrayList<Integer> list1 = new ArrayList<>();
list1.addAll(list);
res1.add(list1);
}
return;
}else{
for(int i =index;i<candidates.length;i++){
if(i>0&&candidates[i]==candidates[i-1]&&!falgs[i-1]) continue;
if (!falgs[i]) {
list.add(candidates[i]);
falgs[i]=true;
combination(candidates, target - candidates[i], list, i + 1);
list.remove(list.size() - 1);
falgs[i]=false;
}
}
}
}
}
这是上一个题“组合”的进阶版,为什么这么说,因为这个题中可能有重复元素并且要求结果中不能出现重复的组合。相信看了我上一篇会觉的这种情况很眼熟,是的,这种情况下并且其要求的是组合,那么我们就可以先对其进行排序,然后根据相同的元素的下一个只能跟上一个元素同时用否则不在判断其分支的策略,来对本题进行求解,当然判断某个元素是否被用到,我们依旧可以采用为何一个Boolean数组的方式。
LeetCode 216、组合总数三
class Solution {
List<List<Integer>> res =new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
if(n<=0||k<=0){
return res;
}
falgs=new Boolean[10];
Arrays.fill(falgs,false);
List<Integer> List= new ArrayList<>();
combination3(n,k,List,1);
return res;
}
public void combination3(int n,int k,List<Integer> list,int start){
if(list.size()==k){
if(n==0){
List<Integer> List1= new ArrayList<>();
List1.addAll(list);
res.add(List1);
}
}else{
for(int i=start;i<=9;i++){
list.add(i);
combination3(n-i,k,list,i+1);
list.remove(list.size()-1);
}
}
}
}
那么这个题的不同点是什么呢?
我们发现这个题在题目中已经规定了组合中不能出现重复的数字,并且只允许出现1-9,那么也就等同于让我们在一个1-9的数组中选择k个数使其相加的和等于n,并且这些元素都只能选择一次,做了这么多题之后,我们已经能很敏锐地捕捉到递归结束的条件在于list的size是否等于k,而子分支也需要对开始位置重新定位,
LeetCode 78、子集
class Solution {
List<List<Integer>> res =new ArrayList<>();
Boolean[] flags;
public List<List<Integer>> subsets(int[] nums) {
if(nums.length==0){
return res;
}
List<Integer> list= new ArrayList<>();
subset( nums,0,list);
return res;
}
public void subset(int[] nums,int start,List<Integer> list){
List<Integer> list1= new ArrayList<>();
list1.addAll(list);
res.add(list1);
for(int i =start;i<nums.length;i++){
list.add(nums[i]);
subset(nums,i+1,list);
list.remove(list.size()-1);
}
}
}
这就是我昨天说的我们不需要对其设置结束条件,并且这其中不包含重复元素。记录其递归回溯的过程即可。
LeetCode 90、子集2
此题已向我们说明一些条件:
数组中含重复元素。
解集中不能含相同的子集。
这就跟上面的情况类似,排序->判断是否应该遍历
class Solution {
List<List<Integer>> res =new ArrayList<>();
Boolean[] falgs;
public List<List<Integer>> subsetsWithDup(int[] nums) {
if(nums.length==0){
return res;
}
falgs=new Boolean[nums.length];
Arrays.sort(nums);
Arrays.fill(falgs,false);
List<Integer> list =new ArrayList<>();
subsets(nums,0,list);
return res;
}
public void subsets(int[] nums,int start,List<Integer> list){
List<Integer> list1 =new ArrayList<>();
list1.addAll(list);
res.add(list1);
for(int i= start;i<nums.length;i++){
if(i>0&&nums[i]==nums[i-1]&&!falgs[i-1]) continue;
if(!falgs[i]){
list.add(nums[i]);
falgs[i]=true;
subsets(nums,i+1,list);
falgs[i]=false;
list.remove(list.size()-1);
}
}
}
}
最后一个题:
LeetCode 二进制总数
class Solution {
public List<String> readBinaryWatch(int num) {
List<String> List =new ArrayList<>();
List<Integer> res =new ArrayList<>();
if(num==0){
List.add("0:00");
return List;
}
time(List,num,res,0);
return List;
}
public void time(List<String> List ,int num,List<Integer> res,int start){
if(res.size()==num){
StringBuilder str =new StringBuilder();
int h =0;
int m=0;
for(int i = 0;i<res.size();i++){
if(res.get(i)<4){
h+=Math.pow(2,res.get(i));
}else{
m+=Math.pow(2,res.get(i)-4);
}
}
if(h>11||m>59) return;
String xh =h+"";
str.append(xh);
str.append(":");
if(m<10){
str.append("0");
}
String mo=m+"";
str.append(mo);
List.add(str.toString());
}else{
for(int i =start;i<10;i++){
res.add(i);
time(List,num,res,i+1);
res.remove(res.size()-1);
}
}
}
}
这道题其实思路是很简单的,依旧是组合问题,为什么这么说呢?
这道题的意思其实还是在这些灯里挑出k个灯,返回其代表的时间。
那么我们就可以把这些灯想成是一个数组,数组从0-9,将0-4定义为小时结果,后面定义为分钟结果,通过对其运算最终将其拼接在stringbuilder中即可。
而且在数组中挑出k个数,这个应该对我们来说不难。依旧同一个数不能被重复选择。
小总结:这些算法的整体结构其实都差不多,所以我们在做题的时候,要能通过思考将题分类,确定其整体框架,然后根据题意,在细微之处对固定套路进行一些变动即可。当然能做剪枝的尽量去做剪枝,能力不足的话也不用勉强,像我这种菜鸡就先不尝试剪枝了。
最后希望北京能好起来。中国加油。