[刷题记录Day 27]Leetcode组合之回溯算法

No.1

题目

组合总和

思路

  • 回溯法
  • 不限制数字使用次数,如何处理?
    • 横向遍历树时,还需要使用startIndex,以避免对同一个组合重复多次搜索
    • 但是在递归下一层时,参数中不需要startIndex + 1,表示允许从startIndex开始搜索
  • 数字集中出现0会怎么样?
    • 无限含不同数量0的组合
  • 考虑给空的candidates数组,怎么处理

递归分析

  1. 全局变量pathresult
  2. 返回值:空,参数:可用数字集,targetstartIndex
  3. 终止条件
    1. 路径累计值和target相等,存储结果到result,返回
    2. 路径累计值已经大于target,返回(剪枝)
    3. 路径走到尽头(耗尽所有可用数字),不存在,数字不限制使用次数
  4. 单层递归逻辑
    1. 处理当前节点
    2. 递归进入下一层搜索
    3. 回溯,抛出当前节点

代码

private List<Integer> path;  
private List<List<Integer>> result;  
  
public void combineHelper(int[] candidates, int target, int startIndex) {  
    if (target == 0) {  
        result.add(new ArrayList<>(path));  
        return;  
    } else if (target < 0) { // 已经超过了target,没有必要继续搜索这一分支  
        return;  
    }  
  
    for (int i = startIndex; i < candidates.length; i++) {  
        path.add(candidates[i]);  
        target -= candidates[i];  
        combineHelper(candidates, target, i); // 不限制单个数字的使用次数,就体现在这里  
        target += candidates[i];  
        path.remove(path.size() - 1);  
    }  
}  
  
public List<List<Integer>> combinationSum(int[] candidates, int target) {  
    path = new ArrayList<>();  
    result = new ArrayList<>();  
    if (candidates.length == 0)  
        return result;  
    combineHelper(candidates, target, 0);  
  
    return result;  
}

No.2

题目

组合总和 II

思路

  • 回溯法,大体和No.1类似
  • 这道题目和组合总和如下区别
    • 本题数组candidates的元素是有重复的,而组合总和无重复元素的数组candidates
  • 新要求:解集不能包含重复的组合,怎么处理?
    • 先对candidates排序,然后在横向遍历时,判断与path末尾的数字是否相同,相同则continue,跳过这个数字

递归分析

  1. 全局变量pathresult
  2. 返回值:空,参数:可用数字集,targetstartIndex
  3. 终止条件
    1. 路径累计值和target相等,存储结果到result,返回
    2. 路径累计值已经大于target,返回(剪枝)
    3. 路径走到尽头(耗尽所有可用数字),返回(剪枝)
  4. 单层递归逻辑
    1. 处理当前节点
    2. 递归进入下一层搜索
    3. 回溯,抛出当前节点

代码

private List<Integer> path;  
private List<List<Integer>> result;  
  
public void combineHelper(int[] candidates, int target, int startIndex) {  
    if (target == 0) {  
        result.add(new ArrayList<>(path));  
        return;  
    } else if (target < 0) {  
        return;  
    }  
  
    if (target > 0 && startIndex >= candidates.length)  
        return;  
  
    for (int i = startIndex; i < candidates.length; i++) {  
        int num = candidates[i];  
        // 在这里去除重复结果  
        if (i > startIndex && num == candidates[i - 1])  
            continue;  
        path.add(num);  
        target -= num;  
        combineHelper(candidates, target, i + 1); // 和不限制元素使用次数情况不同  
        target += num;  
        path.remove(path.size() - 1);  
    }  
}  
  
public List<List<Integer>> combinationSum2(int[] candidates, int target) {  
    path = new ArrayList<>();  
    result = new ArrayList<>();  
    if (candidates.length == 0)  
        return result;  
  
    // 先对candidates排序  
    Arrays.sort(candidates);  
  
    combineHelper(candidates, target, 0);  
    return result;  
}

No.3

题目

分割回文串

思路

  • 先写一个判断回文串的函数
  • 回溯法
  • 这是切割问题,类似组合问题

递归分析

  1. 全局变量pathresult
  2. 返回值:空,参数:原生字符串,splitIndex
  3. 终止条件
    1. 字符串用光了,存储结果,返回
  4. 单层递归逻辑
    1. 处理当前节点
    2. 割下来的字符串是回文串,进入下一层递归
    3. 回溯,抛出当前节点

代码

public boolean judgeReversal(String s) {  
    int len = s.length();  
    // left, right时刻同步变化,所以写在for条件里面  
    for (int left = 0, right = len - 1;left <= right ; left++, right--) {  
        if (s.charAt(left) != s.charAt(right))  
            return false;  
    }  
  
    return true;  
}  
  
private List<String> path;  
private List<List<String>> result;  
  
public void partHelper(String s, int startIndex) { // before, not included  
    if (startIndex >= s.length()) {  
        result.add(new ArrayList<>(path));  
        return;  
    }  
  
    for (int i = startIndex; i < s.length(); i++) {  
        String subStr = s.substring(startIndex, i + 1);  
        path.add(subStr);  
        if (judgeReversal(subStr))  
            partHelper(s, i + 1);  
        path.remove(path.size() - 1);  
    }  
}  
  
public List<List<String>> partition(String s) {  
    path = new ArrayList<>();  
    result = new ArrayList<>();  
    partHelper(s, 0);  
  
    return result;  
}
posted @ 2023-09-11 12:56  喜欢毛绒绒的番茄子  阅读(15)  评论(0)    收藏  举报