[编程题] LeetCode上的backTracking类型的题目-难度Medium

来源:互联网 发布:软件测试行业好吗 编辑:程序博客网 时间:2024/05/29 16:17

最近把LeetCode上的backTracking的题目做了一下,发现都是一个套路~
backTracking链接:https://leetcode.com/tag/backtracking/
还有几道比较难的Medium的题和Hard的题没做出来,后面会继续更新和加详细解法解释~


回溯的入门之子集-Subsets

这种题目都是使用这个套路,就是用一个循环去枚举当前所有情况,然后把元素加入,递归,再把元素移除
按照这个套路来做,可以解决backTracking的问题

public class Solution {    public List<List<Integer>> subsets(int[] nums) {        List<List<Integer>> res = new ArrayList<>();        backTracking(res, new ArrayList<>(), nums, 0);        return res;    }    private void backTracking(List<List<Integer>> res, List<Integer> list, int[] nums, int start){        res.add(new ArrayList<>(list)); //第一步 满足条件的临时集合加入结果集        for(int i = start; i < nums.length; ++i){ //第二步for循环 遍历所有的元素            list.add(nums[i]); //第三步 元素加入临时集合            backTracking(res, list, nums, i + 1); //第四步 回溯            list.remove(list.size() - 1); //第五步 元素从临时集合移除        }    }}

Subsets II

返回数组(里面有重复的数字)的不含重复结果的子集

public class Solution {    public List<List<Integer>> subsetsWithDup(int[] nums) {        List<List<Integer>> res = new ArrayList<>();        Arrays.sort(nums);        backTracking(res, new ArrayList<>(), nums, 0);        return res;    }    private void backTracking(List<List<Integer>> res, List<Integer> list, int[] nums, int start){        if(!res.contains(list)) res.add(new ArrayList<>(list)); //检查是否包含结果,不包含才加入        for(int i = start; i < nums.length; ++i){            list.add(nums[i]);            backTracking(res, list, nums, i + 1);            list.remove(list.size() - 1);        }    }}

Letter Combinations of a Phone Number

手机键盘拨号,给你一串数字,问对应手机九宫格的输入法有可能输出那些字符串。

手机键盘:
这里写图片描述

输入:

“23”

输出:

[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”]

public class Solution {    private String[] letter = new String[] {" ", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};    public List<String> letterCombinations(String digits) {        List<String> res = new ArrayList<>();        if(digits == null || digits.length() == 0) return res;        char[] nums = digits.toCharArray();        backTracking(res, new StringBuilder(), nums, 0);        return res;    }    private void backTracking(List<String> res, StringBuilder build, char[] nums, int start){        if(build.length() == nums.length) res.add(build.toString());        for(int i = start; i < nums.length; ++i){            int index = Integer.parseInt(String.valueOf(nums[i]));            for(int j = 0; j < letter[index].length(); ++j){                build.append(letter[index].charAt(j));                backTracking(res, build, nums, i + 1);                build.deleteCharAt(build.length() - 1);            }        }    }}

Generate Parentheses 括号生成器

public class Solution {    public List<String> generateParenthesis(int n) {        List<String> res = new ArrayList<>();        backTracking(res, new StringBuilder(), 0, 0, n);        return res;    }    private void backTracking(List<String> res, StringBuilder builder, int left, int right, int n){        if(builder.length() == n*2) res.add(builder.toString());        else {            if(left < n){                 builder.append("(");                backTracking(res, builder, left+1, right, n);                builder.deleteCharAt(builder.length()-1);            }            if(right < n && left > right){                builder.append(")");                backTracking(res, builder, left, right+1, n);                builder.deleteCharAt(builder.length()-1);            }        }     }}

Combinations

给你两个整数n和k,返回在1到n个数里面所有可能的k个数字的组合。

public class Solution {    public List<List<Integer>> combine(int n, int k) {        List<List<Integer>> res = new ArrayList<>();        backTracking(res, new ArrayList<>(), n, k, 1);        return res;    }    private void backTracking(List<List<Integer>> res, List<Integer> list, int n, int k, int start){        if(list.size() == k) res.add(new ArrayList(list));        for(int i = start; i <= n; ++i){            list.add(i);            backTracking(res, list, n, k, i + 1);            list.remove(list.size() - 1);        }    }}

Combination Sum

给定一个数组candidates,和一个整数target,返回所有candidates里面元素的组合的和等于target。对candidates里面的元素出现的次数无限制。

例如:

candidate : [2, 3, 6, 7] | target: 7

返回:

这里写图片描述

public class Solution {    public List<List<Integer>> combinationSum(int[] candidates, int target) {        List<List<Integer>> res = new ArrayList<>();        Arrays.sort(candidates);        backTracking(res, new ArrayList<>(), candidates, target, 0);        return res;    }    private void backTracking(List<List<Integer>> res, List<Integer> list, int[] candidate, int target, int start){        if(target < 0) return;        if(target == 0) res.add(new ArrayList<>(list));        else {            for(int i = start; i < candidate.length; ++i){                list.add(candidate[i]);                backTracking(res, list, candidate, target - candidate[i], i);                list.remove(list.size() - 1);            }        }    }}

Combination Sum II

给定一个数组candidates,和一个整数target,返回所有candidates里面元素的组合的和等于target。对candidates里面的元素最多只能出现一次。

例如:

candidate : [10, 1, 2, 7, 6, 1, 5]
target: 8

返回:

这里写图片描述

public class Solution {    public List<List<Integer>> combinationSum2(int[] candidates, int target) {        List<List<Integer>> res = new ArrayList<>();        Arrays.sort(candidates);        backTracking(res, new ArrayList<>(), candidates, target, 0);        return res;    }    private void backTracking(List<List<Integer>> res, List<Integer> list, int[] candidate, int target, int start){        if(target < 0) return;        if(target == 0) res.add(new ArrayList<>(list));        else {            for(int i = start; i < candidate.length; ++i){                if(i > start && candidate[i] == candidate[i - 1]) continue;                list.add(candidate[i]);                backTracking(res, list, candidate, target - candidate[i], i + 1);                list.remove(list.size() - 1);            }        }    }}

Combination Sum III

public class Solution {    public List<List<Integer>> combinationSum3(int k, int n) {        List<List<Integer>> res = new ArrayList<>();        backTracking(res, new ArrayList<>(), k, n, 1);        return res;    }    private void backTracking(List<List<Integer>> res, List<Integer> list, int k, int n, int start){        if(n < 0) return;        if(n == 0 && list.size() == k) res.add(new ArrayList<>(list));        for(int i = start; i <= 9; i++){            list.add(i);            backTracking(res, list, k, n-i, i+1);            list.remove(list.size()-1);        }    }}

Permutations 排列

给你一个数字不重复的数组,求这个数组的所有排列

public class Solution {    public List<List<Integer>> permute(int[] nums) {        List<List<Integer>> res = new ArrayList<>();        backTracking(res, new ArrayList<>(), nums);        return res;    }     private void backTracking(List<List<Integer>> res, List<Integer> list, int[] nums){        if(list.size() == nums.length) res.add(new ArrayList<>(list));        for(int i = 0; i < nums.length; ++i){            if(list.contains(nums[i])) continue; // 跳过重复的            list.add(nums[i]);            backTracking(res, list, nums);            list.remove(list.size() - 1);        }    }}

Palindrome Partitioning 分割回文字串

给你一个字符串s,分割字符串s使得每个子字符串都是回文,返回所有的分割结果。

如s = “aab”
返回:
[
[“aa”,”b”],
[“a”,”a”,”b”]
]

public class Solution {    public List<List<String>> partition(String s) {        List<List<String>> res = new ArrayList<>();        backTracking(res, new ArrayList<>(), s, 0);        return res;    }    private void backTracking(List<List<String>> res, List<String> list, String s, int start){        if(start == s.length()) res.add(new ArrayList<>(list)); //start == s.length()的时候,说明已经带s的最后一个字符了        else {            for(int i = start; i < s.length(); i++){                if(isPalindrome(s, start, i)){                    list.add(s.substring(start, i+1));                    backTracking(res, list, s, i+1);                    list.remove(list.size() - 1);                }            }        }    }    /*     * 判断是否是回文     */    private boolean isPalindrome(String s, int low, int high){        while(low < high){            if(s.charAt(low++) != s.charAt(high--)) return false;        }        return true;    }}

N-Queens

有了 Palindrome Partitioning 分割回文字串 的基础,我们就可以解决经典的 N-皇后 的问题了: N-Queens

设计一种算法,打印n皇后在n*n棋盘上的各种摆法,其中每个皇后都不同行,不同列,也不在对角线上。

public class Solution {    public List<List<String>> solveNQueens(int n) {        List<Integer[]> res = new ArrayList<>();        backTracking(res, new Integer[n], n, 0);        //以下只是把皇后放置在棋盘上        List<List<String>> resList = new ArrayList<>();        for(Integer[] nums: res){            List<String> list = new ArrayList<>();            for(int i = 0; i < nums.length; i++){                StringBuilder sb = new StringBuilder();                for(int j = 0; j < n; j++){                    if(j == nums[i]) sb.append("Q");                    else sb.append(".");                }                list.add(sb.toString());            }            resList.add(list);        }        return resList;    }    /*     * queen[] 是表示:下表i代表第i行的第queen[i]列放置一个皇后     */    private void backTracking(List<Integer[]> res, Integer[] queen, int n, int start){        if(start == n) res.add(queen.clone());        else {            for(int i = 0; i < n; i++){ //不是从start开始                if(checkValid(queen, start, i)){                    queen[start] = i;                    backTracking(res, queen, n, start+1); //不是i+1,i只是和列有关                }            }        }    }    /*     * 检查在位置(row1,col1)是否可以放置皇后     */    private boolean checkValid(Integer[] queen, int row1, int col1){        for(int row2 = 0; row2 < row1; row2++){            int col2 = queen[row2];            if(col2 == col1) return false; //两个皇后放置在同一列上            int colSize = Math.abs(col1 - col2);            int rowSize = row1 - row2;            if(colSize == rowSize) return false; //两个皇后放置在同一对角线上        }        return true;    }}
2 0