1. 程式人生 > >回溯演算法初涉

回溯演算法初涉

什麼是回溯演算法?

回溯演算法也是深度搜索演算法(DFS),也是遞迴。

回溯演算法是最基本的暴力解決演算法,可以很好的解決大多數問題,由此我們需要掌握它。

 

遞迴有兩點要素:

1. 遞迴邊界。

2. 遞迴的邏輯——遞迴"公式"。

遞迴邊界即是需要我們自己尋找的程式出口,這是遞迴的終點,它將返回子問題的解。

遞迴公式則理解為對於問題的合理分解。即將一個大問題,合理的將之簡化為子問題。也就是說將一個複雜的系統通過合理的方式拆解為單位動作。我們需要研究的也就是如何合理分解

 

下面將給出一個遞迴函式框架(並不是固定不變的,會根據問題的變化而改動),可以進行適當的理解。

返回型別 dfs(形參1,形參2,形參3,...,形參n){
    if (遞迴邊界){
        return 子問題的解
    }

    通過合理的方式拆解問題
    
}

 

下面舉幾個例子。

 

71.子集

問題:

給定一組不含重複元素的整數陣列 nums,返回該陣列所有可能的子集(冪集)。

說明:解集不能包含重複的子集。

示例:

輸入: nums = [1,2,3]
輸出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

思路:

這道題要我們返回陣列所有的子集(不包含重複子集)。我們將之拆分:

1. 將輸出分為三部分,分別輸入1位,2位,3位,...,n位。

2. 通過迴圈,將陣列中的後面的數字逐個推進棧中。

3. 建立遞迴邊界,即為判斷容器 vector 中的數字達到 k 值沒有。

 

程式:

class Solution {
public:
    
    vector<vector<int>> res;
    vector<int> tmpv;
    
    vector<vector<int>> subsets(vector<int>& nums) {
        for (int k=0;k<=nums.size();k++)    // 將輸出分為n部分
            dfs(nums,0,k);
        
        return res;
    }
    
    void dfs(vector<int> num, int i,int k){
        if (i == k)    // 判斷是否與輸出數字量相同
            res.push_back(tmpv);
        
        for (int j=i;j<k;j++){    // 迴圈
            tmpv.push_back(num[j]);  // 推入棧中
            dfs(num,j+1,k);    // 遞迴,加入下一個數
            tmpv.pop_back();    // 返回原來的狀態
        }
    }
};

 

46. 全排列

題目:

給定一個沒有重複數字的序列,返回其所有可能的全排列。

示例:

輸入: [1,2,3]
輸出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

 

思路:

題目讓我們返回給定序列所有的排列組合。

由此我們開始拆解問題,將之分成多個子問題:即兩個交換元素(當只有兩個元素時,交換一次即可。)。

從第一個元素開始作為交換點,不斷與後續元素交換,得到新的序列。返回狀態,再從第二個元素開始。。。

程式:

 

class Solution {
public:
    
    vector<vector<int>> res;
    vector<int> tmpv;
    vector<vector<int>> permute(vector<int>& nums) {
        dfs(nums,0);
        return res;
    }
    
    void dfs(vector<int> &nums,int i){
        if (i == nums.size())    //
            res.push_back(nums);
        
        for (int j=i;j<nums.size();j++){
            swap(nums[j],nums[i]);
            dfs(nums,i+1);
            swap(nums[j],nums[i]);
        }
    }
};