回溯算法即递归的算法,其核心的思想是尝试,如果符合,则进一步尝试,知道其符合题意,若不符合,则进行回溯。
这种算法具有明显的模板,要学会套用模板,下面以题目来进行说明。
1. LeetCode Combination Sum
/************************************************************************
* Given a set of candidate numbers (C) and a target number (T), find all unique combinations
* in C where the candidate numbers sums to T.
*
* The same repeated number may be chosen from C unlimited number of times.
*
* Note:
*
* All numbers (including target) will be positive integers.
* Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
* The solution set must not contain duplicate combinations.
*
* For example, given candidate set 2,3,6,7 and target 7,
* A solution set is:
* [7]
* [2, 2, 3]
************************************************************************/
解析:给一个集合2,3,6,7找到其相加为7,很明显的回溯解法,首先加入2,2,2时需要1,不符合,进行回溯2,2,3符合,因此加入输出矩阵中。
下面用代码实现:
class Solution {
public:
void combinationSum(vector<int> &candidates, int target,vector<vector<int> > &res,vector<int> &combination, int begin) {
if (!target) { //满足条件,加入res中
res.push_back(combination);
return;
}
for (int i = begin; i != candidates.size() && target >= candidates[i]; ++i) {
combination.push_back(candidates[i]);
combinationSum(candidates, target - candidates[i], res, combination, i);
combination.pop_back(); //回溯
}
}
vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int> > res;
vector<int> combination;
combinationSum(candidates, target, res, combination, 0);
return res;
}
};
2.LeetCode Combination Sum II
**********************************************************************************
* Given a collection of candidate numbers (C) and a target number (T), find all
* unique combinations in C where the candidate numbers sums to T.
*
* Each number in C may only be used once in the combination.
*
* Note:
*
* > All numbers (including target) will be positive integers.
* > Elements in a combination (a1, a2, … , ak) must be in non-descending order.
* (ie, a1 ≤ a2 ≤ … ≤ ak).
* > The solution set must not contain duplicate combinations.
*
* For example, given candidate set 10,1,2,7,6,1,5 and target 8,
* A solution set is:
* [1, 7]
* [1, 2, 5]
* [2, 6]
* [1, 1, 6]
**********************************************************************************/
与上面一题代码非常的相似,这个要注意的是:
1. 数字不能重复使用
2. 无能有相同的答案
实现如下:
class Solution {
public:
void combinationSum2(vector<int> &candidates, int target,vector<vector<int> > &res,vector<int> &combination, int begin) {
if (!target) {
res.push_back(combination);
return;
}
for (int i = begin; i != candidates.size() && target >= candidates[i]; ++i) {
if (i==begin||candidates[i]!=candidates[i-1]) {
combination.push_back(candidates[i]);
combinationSum2(candidates, target - candidates[i], res, combination, i+1);
combination.pop_back();
}
}
}
vector<vector<int> > combinationSum2(std::vector<int> &candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int> > res;
vector<int> combination;
combinationSum2(candidates, target, res, combination, 0);
return res;
}
};
3 LeetCode N-Queens
/**********************************************************************************
* The n-queens puzzle is the problem of placing n queens on an n×n chessboard
* such that no two queens attack each other.
*
* Given an integer n, return all distinct solutions to the n-queens puzzle.
*
* Each solution contains a distinct board configuration of the n-queens' placement,
* where 'Q' and '.' both indicate a queen and an empty space respectively.
*
* For example,
* There exist two distinct solutions to the 4-queens puzzle:
*
* [
* [".Q..", // Solution 1
* "...Q",
* "Q...",
* "..Q."],
*
* ["..Q.", // Solution 2
* "Q...",
* "...Q",
* ".Q.."]
* ]
**********************************************************************************/
皇后问题:即每一行,每一列,和每个对角线都不能有两个皇后存在。
这个问题是典型的回溯问题,一个个的进行尝试,没什么好说的,code can explain.
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> res;
vector<string> que(n,string(n,'.'));
solveQueue(res,que,0,n);
return res;
}
private:
void solveQueue(vector<vector<string>>& res,vector<string>& que,int row,int& n) {
if (row==n) { //满足条件
res.push_back(que);return;
}
for (int col=0;col!=n;col++) {
if (isValid(que,row,col,n)) { //检查是否符合条件
que[row][col]='Q';
solveQueue(res,que,row+1,n);
que[row][col]='.'; //回溯
}
}
}
bool isValid(vector<string>& que,int row,int col,int& n) {
for (int i=0;i!=row;i++) //column
if (que[i][col]=='Q') return false;
for (int i=row-1,j=col-1;i>=0&&j>=0;i--,j--) //45
if (que[i][j]=='Q') return false;
for (int i=row-1,j=col+1;i>=0&&j<n;i--,j++) //135
if (que[i][j]=='Q') return false;
return true;
}
};
4. LeetCode Sudoku Solver
/**********************************************************************************
*
* Write a program to solve a Sudoku puzzle by filling the empty cells.
*
* Empty cells are indicated by the character '.'.
*
* You may assume that there will be only one unique solution.
*
* A sudoku puzzle...
*
* ...and its solution numbers marked in red.
*
*
**********************************************************************************/
与皇后问题非常的相似,是一个模板。code can explain.
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
solve(board);
}
private:
bool solve(vector<vector<char>>& board) {
for (int r = 0; r < 9; r++) {
for (int c = 0; c < 9; c++) {
if (board[r][c] == '.') {
for (char d = '1'; d <= '9'; d++) {
if (isValid(board, r, c, d)) {
board[r][c] = d;
if (solve(board)) return true;
board[r][c] = '.';
}
}
return false;
}
}
}
return true;
}
bool isValid(vector<vector<char>>& board, int r, int c, char d) {
for (int row = 0; row < 9; row++)
if (board[row][c] == d) return false;
for (int col = 0; col < 9; col++)
if (board[r][col] == d) return false;
for (int row = (r / 3) * 3; row < (r / 3 + 1) * 3; row++)
for (int col = (c / 3) * 3; col < (c / 3 + 1) * 3; col++)
if (board[row][col] == d) return false;
return true;
}
};
矩阵中路径问题
给定一个矩阵和一个字符串,在这个矩阵中找出是否有一个路径包含了这个字符串。
例如:
a b c e
s f c s
a d e e
则,这个矩阵中包含一个bcced的路径
这个题是一个可用深度优先搜索去解决。下面代码实现过程:
#include<iostream>
#include<vector>
#include <string>
using namespace std;
bool valid(vector<vector<char>>& matrix, string& str,vector<vector<int>>& vis,int i, int j,int k) {
int m = matrix.size(), n = matrix[0].size(), len = str.size();
if (i < 0 || i >= m || j < 0 || j >= n || vis[i][j] || matrix[i][j] != str[k])
return false;
if (k == len - 1) return true; //满足条件
vis[i][j] = 1; //标记访问
int next[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
for (int t = 0; t < 4; t++) { //搜索周围的
int x = i + next[t][0];
int y = j + next[t][1];
if (valid(matrix, str, vis, x, y, k + 1))
return true;
}
vis[i][j] = 0; //回溯
return false;
}
bool hasPath(vector<vector<char>>& matrix, string str) {
int m = matrix.size(), n = matrix[0].size(), len = str.size();
vector<vector<int>> vis(m, vector<int>(n, 0));
for (int i=0;i<m;i++)
for (int j = 0; j < n; j++) {
if (valid(matrix, str, vis, i, j, 0))
return true;
}
return false;
}
int main(){
vector<vector<char>> vv = { {'a','b','c','e'},{'s','f','c','s'},{'a','d','e','e' } };
string s = "bcced";
cout << hasPath(vv, s) << endl;
return 0;
}
….未完待续