36-40 有效的数独 - 解数独 - 外观数列 - 组合总和 - 组合总和 II

36. 有效的数


37. 解数独


38. 外观数列

递归

我们要求第n个外观数列,一定要获得第n-1个外观数列

public String countAndSay(int n) {
    if(n == 1){
        return "1";
    }
    String last = countAndSay(n - 1);//得到上一行的字符串
    return getNextString(last);//输出当前行的字符串
}
public String getNextString(String last){
    if(last.length() == 0) return "";
    //得到第 1 个字符重复的次数
    int num = getRepeatNum(last);
    // 次数 + 当前字符 + 其余的字符串的情况
    return num + "" + last.charAt(0) + getNextString(last.substring(num));
}
//得到字符 string[0] 的重复个数,例如 "111221" 返回 3
private int getRepeatNum(String string) {
    int count = 1;
    char same = string.charAt(0);
    for (int i = 1; i < string.length(); i++) {
        if (same == string.charAt(i)) {
            count++;
        } else {
            break;
        }
    }
    return count;
}

优化:递归和StringBuilder结合

public String countAndSay(int n) {
    if (n == 1) {
        return "1";
    }
    StringBuffer res = new StringBuffer();
    String str = countAndSay(n - 1);
    int length = str.length();
    int a = 0;
    for (int i = 1; i < length + 1; i++) {
        if (i == length) {
            return res.append(i - a).append(str.charAt(a)).toString();
        } else if (str.charAt(i) != str.charAt(a) ) {
            res.append(i - a).append(str.charAt(a));
            a = i;
        }
    }
    return res.toString();
}

39. 组合总和(考点)

题目:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。其中candidates 中的数字可以无限制重复被选取。

回溯

每个数字可以用多次,所以backtrace里面可以这样写,因为每个数字都可以使用无数次,所以递归还可以从当前元素开始

    for(int i=0;i<candidates.length;i++){
        path.add(candidates[i]);
        //因为每个数字都可以使用无数次,所以递归还可以从当前元素开始
        backtrace(res,path,candidates,0,remain-candidates[i]);
        path.remove(path.size()-1);
    }

每次递归我们都是从 0 开始,所有数字都遍历一遍。所以会出现重复的组合。改进一下,只需加一个 start 变量即可

    for(int i=start;i<candidates.length;i++){
        path.add(candidates[i]);
        backtrace(res,path,candidates,i,remain-candidates[i]);
        path.remove(path.size()-1);
    }

完整代码

public List<List<Integer>> combinationSum(int[] candidates, int target) {
    List<List<Integer>> res=new ArrayList<>();
    int len=candidates.length;
    if(len==0) return res;
    List<Integer> path=new ArrayList<>();
    backtrace(res,path,candidates,0,target);
    return res;
}
public void backtrace(List<List<Integer>> res,List<Integer> path,int[] candidates, int start,int remain){
    if(remain<0) return;
    if(remain==0) res.add(new ArrayList<>(path));
    //每次递归的时候从start开始,而不是0开始,后者会产生很多重复项
    for(int i=start;i<candidates.length;i++){
        path.add(candidates[i]);
        backtrace(res,path,candidates,i,remain-candidates[i]);
        path.remove(path.size()-1);
    }
}

40. 组合总和 II(考点)

这道题和39题不同的是,这道题数组中的数字只能被选择一次
解题思想还是一样的,我们要做的是怎么过滤掉重复的,首先可以对原数组进行排序,排序之后相同的肯定是挨着的,if(candidates[i] == candidates[i - 1])我们就过滤掉candidates[i],我们就仿照39. 组合总和来写下这道题的答案

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    List<List<Integer>> res=new ArrayList<>();
    int len=candidates.length;
    if(len==0) return res;
    Arrays.sort(candidates);
    List<Integer> path=new ArrayList<>();
    backtrace(res,path,candidates,0,target);
    return res;
}
public void backtrace(List<List<Integer>> res,List<Integer> path,int[] candidates, int start,int remain){
    if(remain<0) return;
    if(remain==0) res.add(new ArrayList<>(path));
    //每次递归的时候从start开始,而不是0开始,后者会产生很多重复项
    for(int i=start;i<candidates.length;i++){
    	//这里去重,注意i的范围
        if(i>start&&candidates[i]==candidates[i-1]){
            continue;
        }
        path.add(candidates[i]);
        //这里改成i+1,因为一个数只能用一次
        backtrace(res,path,candidates,i+1,remain-candidates[i]);
        path.remove(path.size()-1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值