代码随想录Day27 | 39. 组合总和、40. 组合总和 II、131. 分割回文串 | 回溯

73 阅读1分钟

39. 组合总和

题目链接:39. 组合总和

思路: 这道题的关键在于 candidates 中的元素可以复用多次,标准的组合问题通过下一层回溯从i + 1开始来保证不重复使用元素的,如果我想让每个元素被重复使用,我只要把 i + 1 改成 i 即可

class Solution {

    LinkedList<Integer> track = new LinkedList<>();
    List<List<Integer>> res = new LinkedList<>();
    int sum;

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        backtrack(candidates, target, 0);
        return res;
    }

    void backtrack(int[] candidates, int target, int start) {
        if (sum == target) {
            res.add(new LinkedList<>(track));
            return;
        }
        if (sum > target) {
            return;
        }
        for (int i = start; i < candidates.length; i++) {
            track.add(candidates[i]);
            sum += candidates[i];
            backtrack(candidates, target, i);
            track.removeLast();
            sum -= candidates[i];
        }
    }
}

40. 组合总和 II

题目链接:40. 组合总和 II

思路: 我们需要进行剪枝,如果一个节点有多条值相同的树枝相邻,则只遍历第一条,剩下的都剪掉,不要去遍历。体现在代码上,需要先进行排序,让相同的元素靠在一起,如果发现 nums[i] == nums[i-1],则跳过。

class Solution {

    LinkedList<Integer> track = new LinkedList<>();
    List<List<Integer>> res = new LinkedList<>();
    int sum = 0;

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        backtrack(candidates, target, 0);
        return res;
    }

    void backtrack(int[] candidates, int target, int start) {
        if (sum == target) {
            res.add(new LinkedList<>(track));
            return;
        }
        if (sum > target) {
            return;
        }
        for (int i = start; i < candidates.length; i++) {
            if (i > start && candidates[i] == candidates[i - 1]) {
                continue;
            }
            track.add(candidates[i]);
            sum += candidates[i];
            backtrack(candidates, target, i + 1);
            track.removeLast();
            sum -= candidates[i];
        }
    }
}

131. 分割回文串

题目链接:131. 分割回文串

思路: 难点在于如何在代码中实现字符串的切割线,其实startIndex就可以实现切割线的功能,[startIndex, i]就是分割出来的字符串。判断字串是不是回文串,如果不是,continue。

    class Solution {
    List<List<String>> res = new ArrayList<>();
    LinkedList<String> track = new LinkedList<>();

    public List<List<String>> partition(String s) {
        backtrack(s, 0);
        return res;
    }

    private void backtrack(String s, int startIndex) {
        //如果起始位置大于s的大小,说明找到了一组分割方案
        if (startIndex >= s.length()) {
            res.add(new LinkedList(track));
            return;
        }
        for (int i = startIndex; i < s.length(); i++) {
            if (isPalindrome(s, startIndex, i)) {
                String str = s.substring(startIndex, i + 1);
                track.add(str);
            } else {
                continue;
            }
            backtrack(s, i + 1);
            track.removeLast();
        }
        
    }
    //判断是否是回文串
    private boolean isPalindrome(String s, int startIndex, int end) {
        for (int i = startIndex, j = end; i < j; i++, j--) {
            if (s.charAt(i) != s.charAt(j)) {
                return false;
            }
        }
        return true;
    }
}