关于回溯,推荐一个视频:(斯坦福的关于回溯的现场教学三个例子,老师课堂手写代码)
https://www.youtube.com/watch?v=78t_yHuGg-0&t=741s&list=PLnfg8b9vdpLn9exZweTJx44CII1bYczuk&index=18
https://www.youtube.com/watch?v=J_odcqzHGqw&list=PLnfg8b9vdpLn9exZweTJx44CII1bYczuk&index=18
https://www.youtube.com/watch?v=5v6zdfkImms&index=19&list=PLnfg8b9vdpLn9exZweTJx44CII1bYczuk
36. Valid Sudoku
这道题是让你判断现有的数字是不是合法的,也就是说只需要去判断数字,不用去判断空的部分。(其实是数独解法的判断部分)
36题的解析:
9个数组来记录每行的重复情况,用数组下标来表示该数,比如 row[ 2 ] [ 3 ],表示第二行数字3的情况,如果 row[2][3] = 0,说明第三行已记录的没有3; 如果row[2][3] = 1,说明第三行已记录的已经有3,表示重复,直接return false就可以了。(注意下标,2应该是第三行,因为从0开始),为了对应的从0开始,所以数字也是要 board[ i ] [ j ] - '0' - 1
9个数组来计算每列的重复情况,参照上面。
9个数组来计算每隔cubic的重复情况,cubic的计算方法应该是:( i / 3 ) * 3 + ( j / 3 ), 如下图:
当然也可以不选用数组,用个哈希表就可以,哈希表的查找或者增加的操作可以用来判断是不是重复。
Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
- Each row must contain the digits
1-9
without repetition. - Each column must contain the digits
1-9
without repetition. - Each of the 9
3x3
sub-boxes of the grid must contain the digits1-9
without repetition.
A partially filled sudoku which is valid.
The Sudoku board could be partially filled, where empty cells are filled with the character '.'
.
Example 1:
Input:
[
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
Output: true
Example 2:
Input:
[
["8","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being
modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
Note:
- A Sudoku board (partially filled) could be valid but is not necessarily solvable.
- Only the filled cells need to be validated according to the mentioned rules.
- The given board contain only digits
1-9
and the character'.'
. - The given board size is always
9x9
.
bool isValidSudoku(vector<vector<char>>& board) {
int row[9][9] = {0};
int col[9][9] = {0};
int cubic[9][9] = {0};
for(int i = 0; i < board.size(); i++){
for(int j = 0; j < board.size(); j++){
int num = board[i][j] - '0' -1;
if(board[i][j] != '.'){
if(row[i][num] || col[j][num] || cubic[3 * (i/3) + j /3][num])
return false;
row[i][num] = col[j][num] = cubic[3 * (i/3) + j /3][num] = 1;
}
}
}
return true;
}
37. Sudoku Solver:
Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
- Each of the digits
1-9
must occur exactly once in each row. - Each of the digits
1-9
must occur exactly once in each column. - Each of the the digits
1-9
must occur exactly once in each of the 93x3
sub-boxes of the grid.
Empty cells are indicated by the character '.'
.
A sudoku puzzle...
...and its solution numbers marked in red.
Note:
- The given board contain only digits
1-9
and the character'.'
. - You may assume that the given Sudoku puzzle will have a single unique solution.
- The given board size is always
9x9
.
AC代码:
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
solve(board);
}
bool solve(vector<vector<char> > & board){
for(int i = 0; i < board.size(); i++){
for(int j = 0;j < board.size(); j++){
if(board[i][j] == '.'){
for(int k = '1'; k <= '9'; k++){
if(isValid(board,i,j,k)){
board[i][j] = k;
if (solve(board))
return true;
board[i][j] = '.'; //回撤
}
}
return false; // 9 个数都不行就返回false
}
}
}
return true; //最后成功的返回true
}
//只需要判断一行 一列 一个cubic
bool isValid(vector<vector<char>>& board, int rowNum, int colNum, char num){
for(int i = 0; i < 9; i++){
if(board[rowNum][i] == num) return false;
if(board[i][colNum] == num) return false;
}
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++)
if( board[i + rowNum - rowNum%3][j + colNum - colNum%3] == num)
return false;
}
return true;
}
};
39. Combination Sum
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.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
Example 2:
Input: candidates = [2,3,5], target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
AC代码:
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector <vector <int> > res;
vector<int> sol;
search(candidates, 0, target, res, sol);
return res;
}
void search(vector<int> & candidates, int begin, int target, vector<vector<int>> &res, vector<int> &sol){
if(target == 0){
res.push_back(sol);
return;
}
for(int i = begin; i < candidates.size(); i++){
if(target > 0){
sol.push_back(candidates[i]);
search(candidates, i, target - candidates[i], res, sol);
sol.pop_back(); //回溯
}else return; //因为已经有序,后面的都不用再找了
}
}
};
40. Combination Sum II
这道题就是把上一题稍微变一下,只加了两行,也就是:
对相同的 i 进行搜索的时候直接跳过就好,以防发生重复。
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.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
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]
]
AC代码:
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> res;
sort(candidates.begin(), candidates.end());
vector<int > sol;
backTracking(candidates, 0, target, res, sol);
return res;
}
void backTracking(vector<int> & candidates, int begin, int target, vector<vector<int>> &res, vector<int> & sol){
if(target == 0){
res.push_back(sol);
return;
}
for(int i = begin; i < candidates.size(); i ++){
if(candidates[i] <= target ){
sol.push_back(candidates[i]);
backTracking(candidates, i + 1, target - candidates[i], res, sol);
sol.pop_back();
}else
return;
while(candidates[i] == candidates[i+1]) //加了这两行,以防重复
i++;
}
}
};
46. Permutations
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]
]
AC代码:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector <int> > res;
vector<int> sol;
backTracking(res, sol, nums);
return res;
}
void backTracking(vector<vector<int> > &res, vector <int> & sol, vector<int> & nums){
if(sol.size() >= nums.size()){
res.push_back(sol);
return;
}
for(int i = 0; i < nums.size(); i++){
if(!Exist(sol, nums[i])){
sol.push_back(nums[i]);
//print(sol);
backTracking(res, sol, nums);
sol.pop_back();
}
}
}
/*
*在C++的vector中,没有类似java的contains这个操作,所以要自己去判断一下
*/
bool Exist(vector<int> & sol, int num){
vector<int>:: iterator it = sol.begin();
while(it != sol.end()){
if(*it == num) return true;
it++;
}
return false;
}
47. Permutations II
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]
]
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector< vector<int> > res;
if(nums.size() == 0)
return res;
sort(nums.begin(), nums.end());
vector<int > sol;
vector<bool> used(nums.size(), false);
backTracking(res, sol, nums, used);
return res;
}
void backTracking(vector<vector<int> > & res, vector<int> & sol, vector<int > & nums, vector<bool> & used){
if(sol.size() == nums.size()){
res.push_back(sol);
return;
}
//choose => explore => unchoose
int preNum = nums[0]-1;
for(int i = 0; i < nums.size(); i++){
if(used[i] || (nums[i] == preNum)) continue;
preNum = nums[i];
sol.push_back(nums[i]);
used[i] = true;
backTracking(res, sol, nums,used);
sol.pop_back();
used[i] = false;
}
}
};