Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Example:
Input: “23”
Output: [“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
/// Backtracking
/// Time Complexity: O(2^len(s))
/// Space Complexity: O(len(s))
class Solution {
private:
const string letterMap[10] = {
" ", //0
"", //1
"abc", //2
"def", //3
"ghi", //4
"jkl", //5
"mno", //6
"pqrs", //7
"tuv", //8
"wxyz" //9
};
vector<string> res;
/**
* s中保存了此时从digits[0...index-1]翻译得到的一个字母字符串
* 寻找和digits[index]匹配的字母,获得digits[0...index]翻译得到的解
* @param digits
* @param index
* @param s
*/
void findCombination(const string &digits, int index, const string &s){
if(index == digits.size()){
res.push_back(s); //保存s
cout<<"get "<<s<<" , return"<<endl;
return;
}
char c = digits[index];
assert(c >= '0' && c <= '9' && c != '1');
string letters = letterMap[c - '0']; //找到当前的字符对应的字符串
for(int i = 0 ; i < letters.size() ; i ++)
{
cout<<"digits["<<index<<"] = "<<c<<" , user"<<letters[i]<<endl;
findCombination(digits, index+1, s + letters[i]);
}
cout<<"digits["<<index<<"] = "<<c<<" , user"<<"complete, return"<<endl;
return;
}
public:
vector<string> letterCombinations(string digits) {
res.clear();//初始化
if(digits == "")
return res;
findCombination(digits, 0, "");
return res;
}
};
void printVec(const vector<string>& vec){
for(string s: vec)
cout << s << endl;
}
int main() {
printVec(Solution().letterCombinations("234"));
return 0;
}
这个程序的输出结果可以印证了递归调用的一个重要特征-要返回回溯!!
回溯法是暴力解法的一个主要实现手段
原题
Given a string containing only digits, restore it by returning all possible valid IP address combinations.
Example:
Input: “25525511135”
Output: [“255.255.11.135”, “255.255.111.35”]
/// Backtrack
/// Time Complexity: O(2^n)
/// Space Complexity: O(n)
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
vector<int> ip;
dfs(s, 0, ip, res);
return res;
}
private:
void dfs(const string& s, int index, vector<int>& ip, vector<string>& res){
if(index == s.size()){
//4段都匹配完成后
if(ip.size() == 4)
res.push_back(get_string(ip));
return;
}
if(index == 0){
ip.push_back(s[0] - '0');
dfs(s, index + 1, ip, res);
}
else{
int next = ip.back() * 10 + (s[index] - '0');//把IP取出来,计算ip的下一个数
if(next <= 255 && ip.back() != 0){ //如果ip超出了255,并且还有IP还没遍历完的时候
ip.back() = next;//把next给当前的ip
dfs(s, index + 1, ip, res);
ip.back() /= 10;//做递归的回退处理,找出所有可能
}
if(ip.size() < 4){ //当next超出了范围,并且ip还没够4个的时候
ip.push_back(s[index] - '0');//在ip里要新开一个数组,保存那个超出范围的next的最后一个数
dfs(s, index + 1, ip, res);
ip.pop_back();//做递归的回退处理,找出所有可能
}
}
}
string get_string(const vector<int>& ip){
string res = to_string(ip[0]);
for(int i = 1; i < ip.size(); i ++)
res += "." + to_string(ip[i]);
return res;
}
};
Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
Example:
Input: “aab”
Output:
[
[“aa”,“b”],
[“a”,“a”,“b”]
]
这又是一道需要用DFS来解的题目,既然题目要求找到所有可能拆分成回文数的情况,那么肯定是所有的情况都要遍历到,对于每一个子字符串都要分别判断一次是不是回文数,那么肯定有一个判断回文数的子函数,还需要一个DFS函数用来递归,再加上原本的这个函数,总共需要三个函数来求解。我们将已经检测好的回文子串放到字符串数组out中,当s遍历完了之后,将out加入结果res中。那么在递归函数中我们必须要知道当前遍历到的位置,用变量start来表示,所以在递归函数中,如果start等于字符串s的长度,说明已经遍历完成,将out加入结果res中,并返回。否则就从start处开始遍历,由于不知道该如何切割,所以我们要遍历所有的切割情况,即一个字符,两个字符,三个字符,等等。。首先判断取出的子串是否是回文串,调用一个判定回文串的子函数即可,这个子函数传入了子串的起始和终止的范围,若子串是回文串,那么我们将其加入out,并且调用递归函数,此时start传入 i+1,之后还要恢复out的状态。
那么,对原字符串的所有子字符串的访问顺序是什么呢,如果原字符串是 abcd, 那么访问顺序(递归的顺序)为: a -> b -> c -> d -> cd -> bc -> bcd-> ab -> abc -> abcd, 这是对于没有两个或两个以上子回文串的情况。那么假如原字符串是 aabc,那么访问顺序为:a -> a -> b -> c -> bc -> ab -> abc -> aa -> b -> c -> bc -> aab -> aabc,中间当检测到aa时候,发现是回文串,那么对于剩下的bc当做一个新串来检测,于是有 b -> c -> bc,这样扫描了所有情况,即可得出最终答案,代码如下:
class Solution {
public:
vector<vector<string>> partition(string s) {
vector<vector<string>> res;//将out加入结果res中
vector<string> out;//将已经检测好的回文子串放到字符串数组out中
helper(s, 0, out, res);
return res;
}
void helper(string s, int start, vector<string>& out, vector<vector<string>>& res) {
if (start == s.size()) { res.push_back(out); return; }
for (int i = start; i < s.size(); ++i) {
if (!isPalindrome(s, start, i)) continue;//不是回文串就要退出循环
out.push_back(s.substr(start, i - start + 1));//把是回文串的字符串复制进out
helper(s, i + 1, out, res);//递归调用下一个
out.pop_back();//递归调用完,将已经检测好的回文子串放到字符串数组out中
}
}
bool isPalindrome(string s, int start, int end) {
while (start < end) {
if (s[start] != s[end]) return false;
++start; --end;
}
return true;
}
};
我们也可以不单独写递归函数,而是使用原函数本身来递归。首先判空,若字符串s为空,则返回一个包有空字符串数组的数组,注意这里不能直接返回一个空数组,后面会解释原因。然后我们从0开始遍历字符串s,因为是使用原函数当递归,所以无法传入起始位置start,所以只能从默认位置0开始,但是我们的输入字符串s是可以用子串来代替的,这样就相当于起始位置start的作用。首先我们还是判断子串是否为回文串,这里的判断子串还是得用一个子函数,由于起点一直是0,所以只需要传一个终点位置即可。如果子串是回文串,则对后面的整个部分调用递归函数,这样我们会得到一个二维数组,是当前子串之后的整个部分拆分为的回文串的所有情况,那么我们只需将当前的回文子串加入到返回的这些所有情况的集合中。现在解释下之前说的为啥当字符串s为空的时候,要返回一个带有空数组的数组,这是因为当子串就是原字符串s的时候,而是还是个回文串,那么后面部分就为空了,若我们对空串调用递归返回的是一个空数组,那么就无法对其进行遍历,则当前的回文串就无法加入到结果res之中,参见代码如下:
class Solution {
public:
vector<vector<string>> partition(string s) {
vector<vector<string>> res;
if (s.empty()) return {{}};
for (int i = 0; i < s.size(); ++i) {
if (!isPalindrome(s, i + 1)) continue;
for (auto list : partition(s.substr(i + 1))) {
list.insert(list.begin(), s.substr(0, i + 1));
res.push_back(list);
}
}
return res;
}
bool isPalindrome(string s, int n) {
for (int i = 0; i < n / 2; ++i) {
if (s[i] != s[n - 1 - i]) return false;
}
return true;
}
};
Given a collection of distinct integers, return all possible permutations.
Example:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
/// Most Naive Recursive
/// Time Complexity: O(n^n)
/// Space Complexity: O(n)
class Solution {
private:
vector<vector<int>> res;
vector<bool> used;
/**
* p中保存了一个有index个元素的排列
* 向这个排列的末尾添加第index+1个元素,获得一个有index+1个元素的排列
* @param nums
* @param index
* @param p
*/
void generatePermutation(const vector<int>& nums, int index, vector<int>& p){
if(index == nums.size()){
res.push_back(p);//保存结果
return;
}
for(int i = 0 ; i < nums.size() ; i ++)
if(!used[i]){
//将nums[i]添加到p中
used[i] = true;
p.push_back(nums[i]);
generatePermutation(nums, index + 1, p );
//让P和used回到原来的状态
p.pop_back();
used[i] = false;
}
return;
}
public:
vector<vector<int>> permute(vector<int>& nums) {
res.clear();
if(nums.size() == 0)
return res;
used = vector<bool>(nums.size(), false);
vector<int> p;
generatePermutation(nums, 0, p);
return res;
}
};
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
Example:
Input: [1,1,2]
Output:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
/// Most Naive Recursive
/// Time Complexity: O(n^n)
/// Space Complexity: O(n)
class Solution {
private:
vector<vector<int>> res;
vector<bool> used;
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
res.clear();
if(nums.size() == 0)
return res;
used = vector<bool>(nums.size(), false);
sort(nums.begin(), nums.end());
vector<int> p;
generatePermutation(nums, 0, p);
return res;
}
private:
void generatePermutation(const vector<int>& nums, int index, vector<int> &p){
if(index == nums.size()){
res.push_back(p);
return;
}
for(int i = 0 ; i < nums.size() ; i ++)
if(!used[i]){
//这里说当前数字和前一个数字相同,
// 且前一个数字的 used 值为0的时候,必须跳过。
// 这里的前一个数 used 值为0,并不代表前一个数字没有被处理过
// 也可能是递归结束后恢复状态时将 used 值重置为0了
if(i > 0 && nums[i] == nums[i-1] && !used[i-1])
continue;
p.push_back(nums[i]);
used[i] = true;
generatePermutation(nums, index + 1, p);
p.pop_back();
used[i] = false;
}
}
};
Given two integers n and k, return all possible combinations of k numbers out of 1 … n.
Example:
Input: n = 4, k = 2
Output:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
/// Naive Recursive
/// Time Complexity: O(k * C(n, k))
/// Space Complexity: O(k)
class Solution {
private:
vector<vector<int>> res;
/**
* 求解C(n,k),当前已经找到的组合存储在c中,需要从start开始搜索新的元素
* @param n
* @param k
* @param start
* @param c
*/
void generateCombinations(int n, int k, int start, vector<int> &c){
//递归终止条件
if(c.size() == k){
res.push_back(c);
return;
}
for(int i = start ; i <= n ; i ++){
c.push_back( i );
generateCombinations(n, k, i + 1, c);
c.pop_back();
}
return;
}
public:
vector<vector<int>> combine(int n, int k) {
res.clear();
if( n <= 0 || k <= 0 || k > n )
return res;
vector<int> c;
generateCombinations(n, k, 1, c);
return res;
}
};
改进后:
/// Naive Recursive Optimized
/// Time Complexity: O(k * C(n, k))
/// Space Complexity: O(k)
class Solution {
private:
vector<vector<int>> res;
void generateCombinations(int n, int k, int start, vector<int> &c){
if(c.size() == k){
res.push_back(c);
return;
}
// 还有k-c.size()个空位,所以,[i....n]中至少要有k-c.size()个元素,区间是前闭后必
for(int i = start; i <= n - (k - c.size()) + 1 ; i ++){
c.push_back(i);
generateCombinations(n, k, i + 1 ,c);
c.pop_back();
}
return;
}
public:
vector<vector<int>> combine(int n, int k) {
res.clear();
if(n <= 0 || k <= 0 || k > n)
return res;
vector<int> c;
generateCombinations(n, k, 1, c);
return res;
}
};
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
Example 1:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
/// Backtrack
/// Time Complexity: O(n^n)
/// Space Complexity: O(target)
class Solution {
public:
vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
vector<vector<int>> res;
vector<int> cur_res;//保存现有的状态
solve(candidates, 0, target, cur_res, res);
return res;
}
private:
/**
* 递归解决组合问题
* @param candidates
* @param index
* @param target
* @param cur_res
* @param res
*/
void solve(const vector<int> &candidates, int index, int target,
vector<int>& cur_res, vector<vector<int>>& res){
//找到这个组合了
if(target == 0){
res.push_back(cur_res);
return;
}
for(int i = index ; i < candidates.size() ; i ++)
if(target >= candidates[i]){
cur_res.push_back(candidates[i]);
solve(candidates, i, target - candidates[i], cur_res, res);
cur_res.pop_back(); //递归遍历完一遍可以去退栈
}
return;
}
};
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
Each number in candidates may only be used once in the combination.Example 1:
Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
Example 2:
Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
[1,2,2],
[5]
]
class Solution {
public:
/**
* 递归回溯
需要注意的是:
1、在同一层递归树中,如果某元素已经处理并进入下一层递归,那么与该元素相同的值就应该跳过。否则将出现重复。
例如:1,1,2,3
如果第一个1已经处理并进入下一层递归1,2,3
那么第二个1就应该跳过,因为后续所有情况都已经被覆盖掉。
2、相同元素第一个进入下一层递归,而不是任意一个
例如:1,1,2,3
如果第一个1已经处理并进入下一层递归1,2,3,那么两个1是可以同时成为可行解的
而如果选择的是第二个1并进入下一层递归2,3,那么不会出现两个1的解了。
* @param candidates
* @param target
* @return
*/
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int>> res;
vector<int> cur_res;
solve(candidates, 0, target, cur_res, res);
return res;
}
private:
void solve(const vector<int> &candidates, int index, int target,
vector<int>& cur_res, vector<vector<int>>& res){
if(target == 0){
res.push_back(cur_res);
return;
}
for(int i = index ; i < candidates.size() ; i ++){
if(i > index && candidates[i] == candidates[i-1])//要求i大于基准索引,如果该i索引和上一个相等,那就跳过
continue;
if(target >= candidates[i]){
cur_res.push_back(candidates[i]);
solve(candidates, i + 1, target - candidates[i], cur_res, res);
cur_res.pop_back();
}
}
return;
}
};
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Note:
All numbers will be positive integers.
The solution set must not contain duplicate combinations.
Example 1:
Input: k = 3, n = 7
Output: [[1,2,4]]
Example 2:
Input: k = 3, n = 9
Output: [[1,2,6], [1,3,5], [2,3,4]]
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>> res;
vector<int> cur_res;
solve(1,k,n,cur_res,res);//注意是从1开始找,因为找0是没有意义的
return res;
}
private:
void solve(int index, int k, int n,
vector<int>& cur_res, vector<vector<int>>& res){
if (n == 0 && k == 0){
res.push_back(cur_res);
return;
}
if (k==0){
return;
}
for (int i = index; i <= 9; i++) {
if (n >= i){ //注意边界条件
cur_res.push_back(i);
solve(i+1,k-1,n-i,cur_res,res);
cur_res.pop_back();
}
}
return;
}
};
Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.
Example:
board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]
Given word = “ABCCED”, return true.
Given word = “SEE”, return true.
Given word = “ABCB”, return false.
class Solution {
private:
int d[4][2] = {{-1, 0}, {0,1}, {1, 0}, {0, -1}}; //向4个方向移动的位移
int m, n;//行列
vector<vector<bool>> visited;//判断该坐标是否已被访问
/**
* 判断x y是否是合法的坐标
* @param x
* @param y
* @return
*/
bool inArea( int x , int y ){
return x >= 0 && x < m && y >= 0 && y < n;
}
/**
* start from board[startx][starty], find word[index...word.size())
* @param board
* @param word
* @param index
* @param startx
* @param starty
* @return
*/
bool searchWord( const vector<vector<char>> &board, const string& word, int index,
int startx, int starty ){
//assert( inArea(startx,starty) );
if( index == word.size() - 1 )
return board[startx][starty] == word[index];
if( board[startx][starty] == word[index] ){
visited[startx][starty] = true;//标记已访问
//从startx,starty出发,向4个方向寻找
for( int i = 0 ; i < 4 ; i ++ ){
int newx = startx + d[i][0];
int newy = starty + d[i][1];
if( inArea(newx, newy) && !visited[newx][newy] &&
searchWord(board, word, index + 1, newx, newy))
return true;
}
visited[startx][starty] = false;
}
return false;
}
public:
bool exist(vector<vector<char>>& board, string word) {
m = board.size();
assert( m > 0 );
n = board[0].size();
visited = vector<vector<bool>>(m, vector<bool>(n, false));//初始化
for( int i = 0 ; i < board.size() ; i ++ )
for( int j = 0 ; j < board[i].size() ; j ++ )
if( searchWord( board, word, 0 , i, j) )
return true;
return false;
}
};
Given a 2d grid map of '1’s (land) and '0’s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
Input:
11110
11010
11000
00000
Output: 1
Example 2:
Input:
11000
11000
00100
00011
Output: 3
/// Floodfill - DFS
/// Recursion implementation
///
/// Time Complexity: O(n*m)
/// Space Complexity: O(n*m)
class Solution {
private:
int d[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int m, n;
vector<vector<bool>> visited;
bool inArea(int x, int y){
return x >= 0 && x < m && y >= 0 && y < n;
}
/**
* 从grid[x][y]的位置开始,进行floodfill
* 保证(x,y)合法,且grid[x][y]是没有被访问过的陆地
* @param grid
* @param x
* @param y
*/
void dfs(vector<vector<char>>& grid, int x, int y){
//assert(inArea(x,y));
visited[x][y] = true;
for(int i = 0; i < 4; i ++){
int newx = x + d[i][0];
int newy = y + d[i][1];
if(inArea(newx, newy) && !visited[newx][newy] && grid[newx][newy] == '1')
dfs(grid, newx, newy);
}
return;
}
public:
int numIslands(vector<vector<char>>& grid) {
m = grid.size();
if(m == 0)
return 0;
n = grid[0].size();
if(n == 0)
return 0;
for(int i = 0 ; i < m ; i ++)
visited.push_back(vector<bool>(n, false));
int res = 0;
for(int i = 0 ; i < m ; i ++)
for(int j = 0 ; j < n ; j ++)
if(grid[i][j] == '1' && !visited[i][j]){
dfs(grid, i, j);
res ++;
}
return res;
}
};
Given a 2D board containing ‘X’ and ‘O’(the letter O), capture all regions surrounded by ‘X’.
A region is captured by flipping all 'O’s into 'X’s in that surrounded region.
Example:
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
Explanation:
Surrounded regions shouldn’t be on the border, which means that any ‘O’ on the border of the board are not flipped to ‘X’. Any ‘O’ that is not on the border and it is not connected to an ‘O’ on the border will be flipped to ‘X’. Two cells are connected if they are adjacent cells connected horizontally or vertically.
这是道关于 XXOO 的题,有点像围棋,将包住的O都变成X,但不同的是边缘的O不算被包围,跟之前那道 Number of Islands 很类似,都可以用 DFS 来解。
/// BFS
/// Time Complexity: O(m*n)
/// Space Complexity: O(m*n)
///
/// This problem is amazing! Because using DFS will lead to Runtime Error,
/// Because in some specific cases, the recursive depth might be too high
/// The following is an example:
/// OOOOOOOOO
/// XXXXXXXXO
/// OOOOOOOXO
/// OXXXXXOXO
/// OXOOOXOXO
/// OXOXOXOXO
/// OXOXXXOXO
/// OXOOOOOXO
/// OXXXXXXXO
/// OOOOOOOOO
///
/// We can see, in above test case, the complexity of recursive depth is O(n*m),
/// where n and m describe the size of board.
/// Obviously, it's too high!
class Solution {
private:
int m, n;
int d[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};
private:
bool inArea(int x, int y){
return x >= 0 && y >= 0 && x < m && y < n;
}
bool bfs(const vector<vector<char>> &board, int x, int y,
vector<vector<bool>>& visited, vector<pair<int,int>>& record){
queue<pair<int,int>> q;
// return true if we can only get to 'X' during BFS,
// otherwise, return false
bool ret = true;
visited[x][y] = true; //如果被访问过
q.push(pair<int,int>(x, y));
while( !q.empty()){
pair<int, int> cur = q.front();
q.pop();
record.push_back(pair<int, int>(cur.first, cur.second)); //记录要把O变成X的坐标
for(int i = 0 ; i < 4 ;i ++){
int newX = cur.first + d[i][0];
int newY = cur.second + d[i][1];
if(!inArea(newX, newY))
// If newX, newY is not in the area,
// it means we get out of the board in this BFS,
// we need to return false in this case
ret = false;
else if(board[newX][newY] == 'O' && !visited[newX][newY]){
visited[newX][newY] = true;
q.push(pair<int, int>(newX, newY));
}
}
}
return ret;
}
public:
void solve(vector<vector<char>>& board) {
m = board.size();
if(m == 0)
return;
n = board[0].size();
if(n == 0)
return;
vector<vector<bool>> visited(m, vector<bool>(n, false));
vector<pair<int,int>> record;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
if (board[i][j] == 'O' && !visited[i][j]){
// clear record before each time we run BFS
record.clear();
if(bfs(board, i, j, visited, record))
// If BFS return true,
// means from this position,
// we will not get out of the board.
// As a result, we can make every position we visited in this BFS from 'O' to 'X'
for(int k = 0 ; k < record.size() ; k ++)
board[record[k].first][record[k].second] = 'X';
}
return;
}
};
这里再从网上找了一道题:
太平洋大西洋水流
/// Basic Recursive
/// Time Complexity: O(n^n)
/// Space Complexity: O(n)
class Solution {
private:
vector<bool> col, dia1, dia2;
vector<vector<string>> res;
// 尝试在一个n皇后问题中, 摆放第index行的皇后位置
void putQueen(int n, int index, vector<int> &row){
if(index == n){
res.push_back(generateBoard(n, row));
return;
}
for(int i = 0 ; i < n ; i ++)
// 尝试将第index行的皇后摆放在第i列
if(!col[i] && !dia1[index + i] && !dia2[index - i + n - 1]){
row.push_back(i);
col[i] = true;
dia1[index + i] = true;
dia2[index - i + n - 1] = true;
putQueen(n, index + 1, row);
//回溯
col[i] = false;
dia1[index + i] = false;
dia2[index - i + n - 1] = false;
row.pop_back();
}
return;
}
/**
*
* @param n
* @param row
* @return
*/
vector<string> generateBoard(int n, vector<int> &row){
assert(row.size() == n);
vector<string> board(n, string(n, '.'));
for(int i = 0 ; i < n ; i ++)
board[i][row[i]] = 'Q'; //给皇后
return board;
}
public:
vector<vector<string>> solveNQueens(int n) {
res.clear();
col.clear();
for(int i = 0 ; i < n ; i ++)
col.push_back(false);
dia1.clear();
dia2.clear();
//给对角线初始化
for(int i = 0 ; i < 2 * n - 1 ; i ++){
dia1.push_back(false);
dia2.push_back(false);
}
vector<int> row;
putQueen(n, 0, row);
return res;
}
};
/// Basic Recursive
/// Time Complexity: O(n^n)
/// Space Complexity: O(n)
class Solution {
public:
int totalNQueens(int n) {
vector<int> row;
vector<bool> col(n, false), dia1(2 * n - 1, false), dia2(2 * n - 1, false);
return dfs(n, 0, row, col, dia1, dia2);
}
private:
int dfs(int n, int index, vector<int>& row,
vector<bool>& col, vector<bool>& dia1, vector<bool>& dia2){
if(index == n)
return 1;
int res = 0;
for(int i = 0; i < n; i ++)
if(!col[i] && !dia1[index + i] && !dia2[index - i + n - 1]){
row.push_back(i);
col[i] = true;
dia1[index + i] = true;
dia2[index - i + n - 1] = true;
res += dfs(n, index + 1, row, col, dia1, dia2);
col[i] = false;
dia1[index + i] = false;
dia2[index - i + n - 1] = false;
row.pop_back();
}
return res;
}
};
最后再从网上找了一道题巩固一下:
Suduku Solver(数独问题)