回溯法也可以叫做回溯搜索法,它是一種搜索的方式。回溯是遞歸的副產品,只要有遞歸就會有回溯。因爲回溯的本質是窮舉,窮舉所有可能,然後選出我們想要的答案,如果想讓回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是窮舉的本質。
回溯法,一般可以解決如下幾種問題:
組合問題:N個數裏面按一定規則找出k個數的集合
切割問題:一個字符串按一定規則有幾種切割方式
子集問題:一個N個數的集合裏有多少符合條件的子集
排列問題:N個數按一定規則全排列,有幾種排列方式
棋盤問題:N皇后,解數獨等等
回溯搜索的遍歷過程:
回溯算法模板框架如下:
void backtracking(參數) {
if (終止條件) {
存放結果;
return;
}
for (選擇:本層集合中元素(樹中節點孩子的數量就是集合的大小)) {
處理節點;
backtracking(路徑,選擇列表); // 遞歸
回溯,撤銷處理結果
}
}
子集
給你一個整數數組 nums ,數組中的元素 互不相同 。返回該數組所有可能的子集(冪集)。
解集 不能 包含重複的子集。你可以按 任意順序 返回解集。
題解:
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> ans = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
dfs(nums, 0);
return result;
}
public void dfs(int[] nums, int index) {
if (index == nums.length) {
//到最底一級分支了
result.add(new ArrayList<Integer>(ans));
return;
}
ans.add(nums[index]);
dfs(nums, index+1); //繼續向下一級搜索
ans.remove(ans.size()-1); //執行結束後需要對 ans 進行回溯
dfs(nums, index+1);
}
}
全排列
給定一個不含重複數字的數組 nums ,返回其 所有可能的全排列 。你可以 按任意順序 返回答案。
題解:
class Solution {
/**
* 思路:
* n個數全排列,從數學上想,一共有n!種排列方式,
* 因爲第一個位置有n個選擇,第二個位置有(n-1)個選擇,以此類推,所有一共有 n*(n-1)*(n-2)*2*1
* 解題過程就是要模擬這個過程
*
* baseCase 處理完最後一個元素,把當前Array做一份copy添加到答案裏
* backtrack(array, index)
* 從i= [index, n]之間依次選取所有元素進行搜索
* 每次將i和index的元素交換 -> next_state
* dfs(array, index+1)
* 將i和index元素交換回來 -> restore state (回溯狀態)
* @param nums
* @return
*/
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>(); //最終返回結果
dfs(result, nums, 0);
return result;
}
/**
* 回溯算法過程
* @param result
* @param nums
* @param index
*/
private void dfs(List<List<Integer>> result, int[] nums, int index) {
if (index >= nums.length) {
//當前分支搜索完畢,將當前集合遍歷,並存入總集合中
List<Integer> ans = new ArrayList<>();
for (int i=0;i<nums.length;i++) {
ans.add(nums[i]);
}
result.add(ans);
return;
}
//搜索沒有結束,將當前放的位置和剩下的數每一個進行交換,並且調用當前層級的dfs,然後再交換回來
for (int i=index;i<nums.length;i++) {
swap(nums, index, i);
dfs(result, nums, index+1);
swap(nums, i, index);
}
}
public void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}