全排列 ( 回溯)
Leetcode : 给定一个 没有重复 数字的序列,返回其所有可能的全排列。
class Solution {
public:
vector<vector<int>> ans;
vector<vector<int>> permute(vector<int>& nums) {
int n = nums.size();
vector<bool> used(n); // 记录哪些元素已经被使用
vector<int> track; // 记录当前已经载入排列的元素,当track.size()==n时,表示它就是nums所有元素的一种排列
backtrack(nums, n, track, used);
return ans;
}
// 回溯算法 普适 的代码框架
void backtrack(vector<int>& nums, int n, vector<int> &track, vector<bool> &used) {
// 触发结束条件 !!! !(1)
if(n == track.size()) {
ans.push_back(track);
return;
}
// 以下是选择列表 !!!!! (2)
for(int i = 0; i < n; ++i) {
// 剔除无用选择
if(used[i]) continue;
// 做选择 !!!!!!! (3)
used[i] = true;
track.push_back(nums[i]);
// 进入下一层决策树
backtrack(nums, n, track, used);
// 取消选择 !!!!!!! (4)
used[i] = false;
track.pop_back();
}
}
};
字符串 ( 回溯)
牛客网题目 : 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
class Solution {
public:
vector<string> Permutation(string str) {
if(str.empty()) return vector<string>();
vector<string> ans;
dfs(str, 0, ans);
return ans;
}
// str,下标index之前是已经排好的,index之后是还未排的,完全排列好的str放入ans
// str中有重复字符,如果ans不允许有相同的排列,那么ans应该用 unorderede_set<string>
// 最后再 用vec.assign(ust.begin(), ust.end())放入vector中。
void dfs(string str, int index, vector<string> &ans) {
// 注意函数参数str不是传引用,所以后面不需要撤销选择。
if(index==str.length()-1) { // 结束条件是 str完全排好了,也就是index到末尾
ans.push_back(str);
return;
}
for(int i = index; i < str.length(); ++i) {
// 有重复元素就跳过
if(i != index && str[i]==str[index]) continue;
swap(str[i], str[index]);
dfs(str, index+1, ans);
}
}
};
机器人的运动范围 (dfs)
Leetcode题目 : 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
class Solution {
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> visited(m, vector<bool>(n));
return dfs(0, 0, m, n, k, visited);
}
// 以(i,j)点为起始点,深度优先遍历所有可以到达的点。
int dfs(int i, int j, int m, int n, int k,
vector<vector<bool>> &visited) {
// 如果当前访问点 越界 || 数位之和超出限制 || 已经访问过,则返回 0
if (i<0 || i>=m || j<0 || j>=n ||
(check(i) + check(j) > k) ||
visited[i][j]) {
return 0;
}
// 标记已经访问过
visited[i][j] = true;
// 深度优先遍历
return dfs(i+1, j, m, n, k, visited) +
dfs(i-1, j, m, n, k, visited) +
dfs(i, j+1, m, n, k, visited) +
dfs(i, j-1, m, n, k, visited) + 1;
}
// check函数是计算 n 的各个数位之和
int check(int n) {
int sum = 0;
while (n) {
sum += (n % 10);
n /= 10;
}
return sum;
}
};
矩阵中的路径 – 判断字符串在字符矩阵中是否能搜到(dfs)
Leetcode题目 : 如下
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
rows = board.size();
cols = board[0].size();
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
if(dfs(board, word, i, j, 0)) return true;
}
}
return false;
}
private:
int rows, cols; // 记录 board 的行数和列数
// dfs函数,以点(i,j)为起点,在board中搜索字符串 word,
// k 表示当前在搜索的 word 的下标,当 k==word.size()-1 且最后一个字符相同就可输出true;
bool dfs(vector<vector<char>>& board, string word, int i, int j, int k) {
if(i >= rows || i < 0 || j >= cols || j < 0 || board[i][j] != word[k]) return false;
if(k == word.size() - 1) return true;
board[i][j] = '\0';
bool res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) ||
dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
board[i][j] = word[k];
return res;
}
};