Leetcode Backtracking(回溯算法) 刷題筆記

78. Subsets

該題給咱們一個array,要求咱們找到全部不重複的子集
java

輸入: nums = [1,2,3]
輸出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
複製代碼

這裏咱們運用backtracking算法,先sort array在此題中其實並沒有意義,創建一個backtrack方法,在方法中,先創建一個新的ArrayList,而後用for loop添加新的元素,用遞歸向更深處搜索,搜索完後刪除新添加的元素算法

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        backtrack(list, new ArrayList<>(), nums, 0);
        return list;
    }
    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] nums, int start){
        list.add(new ArrayList<>(tempList));
        for(int i = start; i < nums.length; i++){
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, i+1);
            tempList.remove(tempList.size()-1);
        }
    }
}
複製代碼

90. Subsets II

該題與78幾乎同樣,可是涉及到了重複問題,這裏咱們先將array sort,而後比較當前位與前一位,若是相同則跳過當前位。數組

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(nums);
        backtrack(list, new ArrayList<>(), nums, 0);
        return list;
    }
    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] nums, int start){
        list.add(new ArrayList<>(tempList));
        for(int i = start; i < nums.length; i++){
            if(i > start && nums[i] == nums[i-1]) continue;
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, i + 1);
            tempList.remove(tempList.size()-1);
        }
    }
}
複製代碼

77. Combinations

給定兩個整數 n 和 k,返回 1 ... n 中全部可能的 k 個數的組合。bash

輸入: n = 4, k = 2
輸出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
複製代碼

仍然採用backracking,寫一個backtrack helper function,而後檢測是否size是k,若是是k則把該tempList加入result listoop

class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> list = new ArrayList<>();
        if(n == 0 || k == 0) return list;
        backtrack(list, new ArrayList<>(), 0, n, k);
        return list;
    }
    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int start, int n, int k){
        if(tempList.size() == k) list.add(new ArrayList<>(tempList));
        for(int i=start; i<n; i++){
            tempList.add(i+1);
            backtrack(list, tempList, i+1, n, k);
            tempList.remove(tempList.size()-1);
        }
    }
}
複製代碼

39. Combinations Sum

給定一個無重複元素的數組 candidates 和一個目標數 target ,找出 candidates 中全部可使數字和爲 target 的組合。spa

candidates 中的數字能夠無限制重複被選取。code

輸入: candidates = [2,3,5], target = 8,
所求解集爲:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]
複製代碼

該題與以前的題目思路徹底相同,只不過斷定條件爲target當前與0的關係,若是等於0則直接添加,小於0則剪枝,大於0則繼續向下探索,難點在於,遞歸時的i爲0,由於每一個數字能夠取無限次遞歸

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> list = new ArrayList<>();
        backtrack(list, new ArrayList<>(), candidates, target, 0);
        return list;
    }
    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] candidates, int target, int start){
        if(target < 0) return;
        else if(target == 0) list.add(new ArrayList<>(tempList));
        else{
            for(int i=start; i<candidates.length; i++){
                tempList.add(candidates[i]);
                backtrack(list, tempList,candidates, target-candidates[i], i);
                tempList.remove(tempList.size()-1);
            }
        }
    }
}
複製代碼

40. Combinations Sum II

思路徹底相同,先sort而後斷定當前的數字與前一個數字是否相等,若是相等則跳過rem

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

216. Combinations Sum III

找出全部相加之和爲 n 的 k 個數的組合。組合中只容許含有 1 - 9 的正整數,而且每種組合中不存在重複的數字get

77 題和 40 題的結合題,須要統計還剩餘的n,並且要斷定當前的tempList的size是否爲k,能夠直接用一個1-9的array也能夠直接用進for loop

class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> list = new ArrayList<>();
        if(n == 0 || k == 0) return list;
        backtrack(list, new ArrayList<>(), n, k, 0);
        return list;
    }
    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int n, int k, int start){
        if(n == 0){
            if(tempList.size() == k) list.add(new ArrayList<>(tempList));
            else return;
        }
        else if(n < 0) return;
        else{
            for(int i = start; i < 9; i++){
                tempList.add(i+1);
                backtrack(list, tempList, n-i-1, k, i+1);
                tempList.remove(tempList.size()-1);
            }
        }
    }
}
複製代碼

377. Combinations Sum IV

這道題能夠用backtracking的作法,可是會超時,該用dp解法

dp[i] = 每個能到dp[i]的step的數量總和

class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target+1];
        dp[0] = 1;
        for(int i = 0; i < dp.length; i++){
            for(int num:nums){
                dp[i] += dp[i-num];
            }
        }
        return dp[target];
    }
}
複製代碼

46. Permutations

給定一個不重複的數組,返回全部的排列組合

輸入: [1,2,3]
輸出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]
複製代碼

Main function 與以前全部題目相同,斷定條件爲是否長度爲nums.length,爲true則獲取了所有元素,在for loop中要斷定當前的tempList裏是否已經包含了當前元素,若是包含則跳過(剪枝)

class Solution {
    public List<List<Integer>> permutations(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        backtrack(list, new ArrayList<>(), nums);
        return list;
    }
    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] nums){
        if(tempList.size() == nums.length) list.add(new ArrayList<>(tempList ));
        for(int i = 0; i < nums.length; i++){
            if(tempList.contains(nums[i])) continue;
            tempList.add(nums[i]);
            backtrack(list, tempList, nums);
            tempList.remove(tempList.size()-1);
        }
    }
}
複製代碼
相關文章
相關標籤/搜索