回溯算法

"learning……"

Posted by Ryan on January 7, 2025

就算风吹散了冰雪,想念也会留存下来。

算法描述

回溯法(backtracking)是优先搜索的一种特殊情况,又称为试探法,常用于需要记录节点状态的深度优先搜索。通常来说,排列、组合、选择类问题使用回溯法比较方便。顾名思义,回溯法的核心是回溯。在搜索到某一节点的时候,如果我们发现目前的节点(及其子节点)并不是需求目标时,我们回退到原来的节点继续搜索,并且把在目前节点修改的状态还原。这样的好处是我们可以始终只对图的总状态进行修改,而非每次遍历时新建一个图来储存状态。在具体的写法上,它与普通的深度优先搜索一样,都有 [修改当前节点状态]→[递归子节 点] 的步骤,只是多了回溯的步骤,变成了 [修改当前节点状态]→[递归子节点]→[回改当前节点状态]。

两个小诀窍,一是按引用传状态,二是所有的状态修改在递归完成后回改。 回溯法修改一般有两种情况,一种是修改最后一位输出,比如排列组合;一种是修改访问标 记,比如矩阵里搜字符串。

全排列

leecode46

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> result;
        vector<bool> used(nums.size(),false);
        vector<int> current;
        func(nums,used,current,result);

        return result;
    }
private:
void func(vector<int>& nums,vector<bool>& used,vector<int>& current,vector<vector<int>>& result)
{
    if(current.size()==nums.size())
    {
        result.push_back(current);
        return;
    }

    for(int i =0;i<nums.size();i++)
    {
        if(used[i]) continue;
        current.push_back(nums[i]);
        used[i]=true;
        func(nums,used,current,result);
        current.pop_back();
        used[i] = false;
    }
}
};

组合

leetcode77

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
private:
    void bt(int& n, int& k,int start,vector<int>& current,vector<bool>&used,vector<vector<int>>&result)
    {
        if(current.size()==k)
        {
            result.push_back(current);
            return;
        }
        for(int i=start;i<=n;++i)
        {
            if(used[i])continue;
            used[i]=true;
            current.push_back(i);
            bt(n,k,i+1,current,used,result);
            used[i]=false;
            current.pop_back();

        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>>result;
        vector<int> current;
        vector<bool>used(n+1,false);
        bt(n,k,1,current,used,result);
        return result;
    }
};

搜索

leetcode79

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
private:
    bool bt(vector<vector<char>>& board, string& word,int index,int row,int column)
    {
        if(index==word.size()) return true;
        if(row<0||column<0||row>=board.size()||column>=board[0].size()||word[index]!=board[row][column]) return false;
        //找到了
        char temp=board[row][column];
        board[row][column]='#';
        bool find=bt(board,word,index+1,row-1,column)||bt(board,word,index+1,row+1,column)||bt(board,word,index+1,row,column-1)||bt(board,word,index+1,row,column+1);
        board[row][column]=temp;
        return find;
    }
public:
    bool exist(vector<vector<char>>& board, string word) {
        for(int i=0;i<board.size();i++)
        {
            for(int j=0;j<board[0].size();j++)
            {
                if(bt(board,word,0,i,j)) return true;
            }
        }
        return false;
    }
};

放置方案

leetcode.51.N皇后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
    void bt(int& n,int row,vector<string>& board,unordered_set<int>& columns,unordered_set<int>& diagonals1,unordered_set<int>& diagonals2,vector<vector<string>>&result)
    {
        if(row==n)
        {
            result.push_back(board);
            return;
        }
        for(int col=0;col<n;++col)
        {
            if(columns.count(col)||diagonals1.count(row+col)||diagonals2.count(row-col)) continue;

            board[row][col]='Q';
            columns.insert(col);
            diagonals1.insert(row+col);
            diagonals2.insert(row-col);
            bt(n,row+1,board,columns,diagonals1,diagonals2,result);
            board[row][col]='.';
            columns.erase(col);
            diagonals1.erase(row+col);
            diagonals2.erase(row-col);
        }
    }
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>>result;
        vector<string> board(n,string(n,'.'));//初始化棋盘
        unordered_set<int> columns;
        unordered_set<int> diagonals1;
        unordered_set<int> diagonals2;
        bt(n,0,board,columns,diagonals1,diagonals2,result);
        return result;
    }
};

练习

leetcode.133.分割回文串
leetcode.78.子集