Leetcode学习:五大算法之回溯算法

1 简介

1.1 介绍

百度百科给出的定义如下:
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

显而易见,这个算法和深度优先遍历有着紧密的联系,都是“一走走到头,走到头就回身到下一个岔路口继续走到头”的类型。但不同于DFS的是需要有一个“状态重置”的操作,因为每一次“走到头”都对应到了一个解,返回时若没有状态重置就相当于又一次重复,且丢失了解空间的其他解。

1.2 算法核心

回溯 = DFS + 状态重置 (+ 剪枝)

2 解答模板

void backTrack(track ,allChoise)
{
    
    
	if('结束条件')//到达了最底层
	{
    
    
		'结束操作';
		return;
	}
	for(i : allChoise)
	{
    
    
		allChoise[i] = true;
		backTrack(track+1, allChoise)//回溯:本质是DFS
		allChoise[i] = false;//状态重置
	}
}

3 例题

根据解答模板,我们可以将以下回溯法的经典例题套进去,来看一下回溯的威力。

3.1 全排列问题

class Solution {
    
    
public:
    vector<vector<int>> permute(vector<int>& nums) {
    
    
        int begin = 0;
        int end = nums.size();

        vector<int> result;
        vector<vector<int>> ret;

        dfs(nums,result,ret,begin,end);
        return ret;
    }

    void dfs(vector<int>& nums, vector<int> result, vector<vector<int>>& ret, int begin, int end)
    {
    
    
        if(begin == end - 1)
        {
    
    
            ret.push_back(nums);
            return;   
        }

        for(int  i = begin; i < end; i++)
        {
    
    
            swap(nums[begin],nums[i]);
            result.push_back(nums[i]);
            
            dfs(nums,result,ret,begin+1,end);

            swap(nums[begin],nums[i]);
            result.pop_back();
                
        }

    }

    void swap(int& a, int& b)
    {
    
    
        int temp = a;
        a = b;
        b = temp;
    }
};

3.2 N皇后问题

#include<iostream>
#include<vector>

using namespace std;

vector<vector<string>> ans;//存储N皇后的解

bool isok(vector<int>& record, int row)//record[row]就是col
{
    
    
	for (int i = 0; i < row; i++)
	{
    
    
		if (record[i] == record[row]
			|| row - record[row] == i - record[i]
			|| row + record[row] == i + record[i])
		{
    
    
			return false;
		}		
	}
	return true;
}

void findQueue(int row, int n, vector<string>&temp, vector<int>& record)
{
    
    
	if (row == n)//N皇后有解了
	{
    
    
		ans.push_back(temp);//把解放进全部解空间中
		return;
	}
	for (int col = 0; col < n; col++)
	{
    
    
		record[row] = col;

		if (isok(record, row))//回溯的过程:record表示在第几列(这一行的第几个位置),l表示在第几行
		{
    
    
			temp[row][col] = 'Q';//设为Q递归回溯一下
			findQueue(row + 1, n, temp, record);//去下一行找
			temp[row][col] = '.';//不论找没找到,回归原始状态继续找
		}
	}
}

vector<vector<string>> solveNQueens(int n)
{
    
    
	string s = "";
	vector<int> record(n);//初始化为n个0
	for (int i = 0; i < n; i++)
	{
    
    
		s += '.';
	}
	vector<string> temp(n, s);//初始化为全是.的nxn的二维数组


	findQueue(0, n, temp, record);//findQueue
	return ans;
}



int main()
{
    
    
	vector<vector<string>> ret = solveNQueens(4);

	system("pause");
	return 0;
}

3.3 解数独问题

bool isValidPart(char **board, int i, int j, int *a)
{
    
    
    char c = board[i][j];
    if(c != '.')
    {
    
    
        int index = c - '1';
        if(a[index]==1)return false;
        else a[index]=1;
    }
    return true;
}

bool isValidSudoku(char** board, int boardRowSize, int boardColSize)
{
    
    
    if(boardRowSize != 9|| boardColSize != 9)
    	return false;
    int a[9]={
    
    0};  //标记一行
    int b[9]={
    
    0};  //标记一列
    int c[9][9]={
    
    0}; //c[i]标记一个9宫格
    
    for(int i = 0; i < 9; i++)
    {
    
    
        memset(a,0,sizeof(int)*9);
        memset(b,0,sizeof(int)*9);
        
        for(int j = 0; j < 9; j++)
        {
    
    
            if(isValidPart(board, i, j, a)==false)
            	return false;
            if(isValidPart(board, j, i, b)==false)
            	return false;
            if(isValidPart(board, i, j, c[(i/3)*3 + j/3])==false)
            	return false;
        }
    }
    return true;
}

猜你喜欢

转载自blog.csdn.net/weixin_42979679/article/details/103654142