回溯系列--11个题

组合问题

第77题. 组合

题⽬链接:https://leetcode-cn.com/problems/combinations/

给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。

⽰例: 输⼊: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]

class Solution {

    List<List<Integer>> result = new ArrayList<>();
    // List<Integer> path = new ArrayList<>(); LinkedList增添的时间复杂度更低
    LinkedList<Integer> path = new LinkedList<>(); 

    public List<List<Integer>> combine(int n, int k) {
        // backtraking(n, k, 0);  返回范围 [1, n] 中所有可能的 k 个数的组合。所以index从1开始
        backtraking(n, k, 1);
        return result;
    }

    void backtraking(int n, int k, int index) {
        if(path.size() == k) {
            // result.add(path); new ArrayList<>() 将LinkedList类型的path转换为ArrayList类型
            result.add(new ArrayList<>(path));
            return;
        }

        for(int i = index; i <= n; i++){
            path.add(i);
            // backtraking(n, k , index + 1);
            backtraking(n, k ,i + 1);
            path.remove(path.size() - 1);
            // path.removeLast();
        }
    }
}

第216题.组合总和III

链接:https://leetcode-cn.com/problems/combination-sum-iii/

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合 中不存在重复的数字。 说明: 所有数字都是正整数。 解集不能包含重复的组合。

⽰例 1: 输⼊: k = 3, n = 7 输出: [[1,2,4]]

⽰例 2: 输⼊: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();

    public List<List<Integer>> combinationSum3(int k, int n) {
        backtracking(k, n, 0, 1);
        return result;
    }
    
    void backtracking(int k, int n,int sum, int index) {
        if(sum == n && path.size() == k) {
            result.add(new ArrayList<>(path));
            return;
        }

        for(int i = index; i <= 9 && n >= sum + i; i++) {
            path.add(i);
            sum += i;
            backtracking(k, n, sum, i + 1);
            sum -= i;
            path.remove(path.size() - 1);
        }
    }
}

17.电话号码的字母组合

题⽬链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/

给定⼀个仅包含数字 2-9 的字符串,返回所有它能表⽰的字母组合。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

⽰例: 输⼊:"23" 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

说明:尽管上⾯的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

class Solution {
     String[] letterMap = new String[]{
            "",//0
            "",//1
            "abc",//2
            "def",//3
            "ghi",//4
            "jkl",//5
            "mno",//6
            "pqrs",//7
            "tuv",//8
            "wxyz"//9
        };
    List<String> result = new ArrayList<>();
    StringBuilder path = new StringBuilder();
    public List<String> letterCombinations(String digits) {
        if(digits == null || digits.length() == 0) return result;
       backTracking(digits, 0);
       return result;
    }

    void backTracking(String digits, int index) {
        if(index == digits.length()) {
            result.add(path.toString());
            return;
        }
        String s = letterMap[digits.charAt(index) - '0'];
        for(int i = 0; i < s.length(); i++){ //对每个按键的水平遍历
            path.append(s.charAt(i));
            backTracking(digits, index + 1); //对不同按键的深度递归
            path.deleteCharAt(path.length() - 1);
        }
    }
}

39. 组合总和

题⽬链接:https://leetcode-cn.com/problems/combination-sum/

给定⼀个⽆重复元素的数组 candidates 和⼀个⽬标数 target ,找出 candidates 中所有可以 使数字和为 target 的组合。 candidates 中的数字可以⽆限制重复被选取。

说明: 所有数字(包括 target)都是正整数。 解集不能包含重复的组合。

⽰例 1: 输⼊:candidates = [2,3,6,7], target = 7, 所求解集为: [ [7], [2,2,3] ]

⽰例 2: 输⼊:candidates = [2,3,5], target = 8, 所求解集为: [ [2,2,2,2], [2,3,3], [3,5] ]

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList path = new LinkedList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        backtracking(candidates, target, 0, 0);
        return result;
    }

    void backtracking(int[] candidates, int target, int sum, int index) {
        if(target == sum) {
            // result.add(path);
            result.add(new ArrayList<>(path));
            return;
        }

        for(int i = index; i < candidates.length && target >= sum + i; i++){ //target >= sum + i要提前排序
            path.add(candidates[i]);
            sum += candidates[i];
            backtracking(candidates, target, sum, i);
            sum -= candidates[i];
            path.remove(path.size() - 1);
        }
    }
}

40.组合总和II

题⽬链接:https://leetcode-cn.com/problems/combination-sum-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] ]

class Solution {
    // public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
    LinkedList path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        used = new boolean[candidates.length];
        Arrays.fill(used, false);
        Arrays.sort(candidates);
        backtracking(candidates, target, 0, 0);
        return result;
    }

    void backtracking(int[] candidates, int target, int sum, int index) {
        if(target == sum) {
            // result.add(path);
            result.add(new ArrayList<>(path));
            return;
        }

        // for(int i = index; i < candidates.length && target >= sum + i; i++){ //target >= sum + i要提前排序
        for(int i = index; i < candidates.length && target >= sum + candidates[i]; i++){
        // if(i > 0 && candidates[i-1] == candidates[i] && used[i - 1] == false){
            if(i > 0 && candidates[i-1] == candidates[i] && used[i - 1] == false){
            continue;
        }
            path.add(candidates[i]);
            sum += candidates[i];
            used[i] = true;
            backtracking(candidates, target, sum, i + 1);
            used[i] = false;
            sum -= candidates[i];
            path.remove(path.size() - 1);
        }
    }
    }

分割问题

131.分割回⽂串

题⽬链接:https://leetcode-cn.com/problems/palindrome-partitioning/

给定⼀个字符串 s,将 s 分割成⼀些⼦串,使每个⼦串都是回⽂串。 返回 s 所有可能的分割⽅案。

⽰例: 输⼊: "aab" 输出: [ ["aa","b"], ["a","a","b"] ]

class Solution {
    List<List<String>> result = new ArrayList<>();
    LinkedList path = new LinkedList<>();
    public List<List<String>> partition(String s) {
        backtracking(s, 0);
        return result;
    }

    void backtracking(String s, int index) {
        if(index == s.length()) {
            // result.add(path);
            result.add(new ArrayList(path));
            return;
        }

        for(int i = index; i < s.length(); i++) {
            if(isvalid(s, index ,i)) {
                //  path.add(s.subStr(i, index));
                // path.add(s.substring(i+1, index));
                path.add(s.substring(index, i+1));
                backtracking(s, i+1);
                path.removeLast();
            }else {
                continue;
            }
             
        }

    }
    
        boolean isvalid(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;
    }
}

子集问题

第78题. ⼦集

题⽬地址:https://leetcode-cn.com/problems/subsets/

给定⼀组不含重复元素的整数数组 nums,返回该数组所有可能的⼦集(幂集)。

说明:解集不能包含重复的⼦集。 

⽰例: 输⼊: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList path = new LinkedList<>();
   
    public List<List<Integer>> subsets(int[] nums) {
        
        backStraking(nums, 0);
        return result;
    }

    void backStraking(int[] nums, int index) {
        result.add(new ArrayList<>(path));

        if(index >= nums.length) {
            return;
        }

        for(int i = index; i < nums.length; i++) {
           
            path.add(nums[i]);
            // backStraking(nums, index +1);  怎么能用index呢?!
            backStraking(nums, i +1);
            path.removeLast();
           
        }
    }
}

491.递增⼦序列

题⽬链接:https://leetcode-cn.com/problems/increasing-subsequences/

给定⼀个整型数组, 你的任务是找到所有该数组的递增⼦序列,递增⼦序列的长度⾄少是 2。

⽰例: 输⼊: [4, 6, 7, 7] 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

说明: 给定数组的长度不会超过15。

·        数组中的整数范围是 [-100,100]。

        给定数组中可能包含重复数字,相等的数字应该被视为递增的⼀种情况。

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
        backtracking(nums,0);
        return result;
    }

    void backtracking(int[] nums,int index) {
        if(path.size() > 1) { //递增子序列长度至少为2
            result.add(new ArrayList<>(path));
        }

        if(index == nums.length){
            return;
        }

        boolean[] used = new boolean[201]; //同一层相同结点不能重复
        for(int i = index; i < nums.length; i++) {
            //纵向判断递增
            if(path.size() > 0 && nums[i] < path.get(path.size() - 1)) {
                continue;
            }
            //横向判断元素是否重复(序列无序)
            if(used[nums[i] + 100] == true) {
                continue;
            }

            // used[nums[i]] = true; 因为下标没有负数
            used[nums[i] + 100] = true;
            path.add(nums[i]);
            backtracking(nums, i + 1);
            path.removeLast();
           

        }
    }
}

排列问题

46.全排列

题⽬链接:https://leetcode-cn.com/problems/permutations/

给定⼀个 没有重复 数字的序列,返回其所有可能的全排列。

⽰例: 输⼊: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> permute(int[] nums) {
        boolean[] used = new boolean[nums.length + 1]; 
        Arrays.fill(used, false);
        backtracking(nums,used);
        return result;
    }

     //同一树枝标记用过 used[i] == true
     //将used作为参数传递 比较的是同一树枝和同一树层
     //将used放在for循环上面,比较的是for循环是否有重复元素
    void backtracking(int[] nums, boolean[] used) {
        if(path.size() == nums.length) {
            result.add(new ArrayList<>(path));
            return;
        }

        for(int i = 0; i < nums.length; i++) {
            if(used[i] == true) {
                continue;
            }
            used[i] = true;
            path.add(nums[i]);
            backtracking(nums, used);
            path.remove(path.size() - 1);
            used[i] = false;
        }
    }
}
   

47.全排列 II

题⽬链接:https://leetcode-cn.com/problems/permutations-ii/

给定⼀个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

⽰例 1: 输⼊:nums = [1,1,2] 输出: [[1,1,2], [1,2,1], [2,1,1]]

⽰例 2: 输⼊:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提⽰: 1 <= nums.length <= 8 -10 <= nums[i] <= 10

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    int len;
    public List<List<Integer>> permuteUnique(int[] nums) {
        len = nums.length;
        boolean[] used = new boolean[nums.length + 1]; //[]是长度  <>是范型  ()是内容
        Arrays.fill(used, false);
        Arrays.sort(nums);
        backTracking(nums,used);
        return result;
    }

    void backTracking(int[] nums, boolean[] used){
        if(path.size() == nums.length) {
            result.add(new ArrayList<>(path));
            return;
        }

        for(int i = 0; i < len; i++) {
            //纵向判断
            if(used[i] == true) continue;
            //横向判断  原序列需要排序
            if(i > 0 && nums[i] == nums[i-1] && used[i-1] == false) continue;

            used[i] = true;
            path.add(nums[i]);
            backTracking(nums, used);
            path.removeLast();
            used[i] = false;
        }
    }
}

棋盘问题

第51题. N皇后

题⽬链接: https://leetcode-cn.com/problems/n-queens/ n

皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

8 皇后问题的⼀种解法:

给定⼀个整数 n,返回所有不同的 n 皇后问题的解决⽅案。 每⼀种解法包含⼀个明确的 n 皇后问题的棋⼦放置⽅案,该⽅案中 'Q' 和 '.' 分别代表了皇后 和空位。

⽰例: 输⼊: 4 输出: [ [".Q..",  "...Q", "Q...", "..Q."],["..Q.",  "Q...", "...Q", ".Q.."] ] 解释: 4 皇后问题存在两个不同的解法。

class Solution {
    List<List<String>> result = new ArrayList<>();
    
    public List<List<String>> solveNQueens(int n) {
        char[][] chessboard = new char[n][n];
        for(char[] c : chessboard) {
            Arrays.fill(c,'.');
        }
        backtracking(n, 0, chessboard);
        return result;

    }

    void backtracking(int n, int row, char[][] chessboard){
        if(row == n) {
            result.add(Array2List(chessboard));
            return;
        }

        for(int col = 0; col < n; col++) { //行和列都是从0开始
            if(isvalid(n,row,col,chessboard)) {
                chessboard[row][col] = 'Q';
                backtracking(n, row + 1, chessboard);
                chessboard[row][col] = '.';
            }
        }
    }

    public List<String> Array2List(char[][] chessboard) {
        List<String> list = new ArrayList<>();
        
        for (char[] c : chessboard) {
            list.add(String.copyValueOf(c));
        }
        return list;
    }

    public boolean isvalid(int n, int row, int col, char[][] chessboard) {
        // 检查列
        for (int i=0; i<n; ++i) {
            if (chessboard[i][col] == 'Q') {
                return false;
            }
        }

        // 检查45度对角线
        for (int i=row-1, j=col-1; i>=0 && j>=0; i--, j--) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }

        // 检查135度对角线
        for (int i=row-1, j=col+1; i>=0 && j<=n-1; i--, j++) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值