基础知识
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就 “回溯” 返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为 “回溯点”。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
面试题一
幂集。编写一种方法,返回某集合的所有子集。集合中不包含重复的元素。
说明:解集不能包含重复的子集。
算法思路:
代码:
//比较常见的剪枝方法,当前层的下一层的元素是当前层元素后面的全部元素,当遍历到最后一个元素的时候返回。
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void subgenerate(vector<int>& nums,int ind) {
if(ind == nums.size())
return ;
else {
for(int i = ind;i < nums.size();i++) {
path.push_back(nums[i]);
res.push_back(path);
subgenerate(nums,i + 1);
path.pop_back();
}
}
}
vector<vector<int>> subsets(vector<int>& nums) {
if(nums.size() == 0)
return res;
res.push_back(path); //把空集合加入其中
subgenerate(nums,0);
return res;
}
};
面试题二
给定一个长度为N的字符串,求它的字母的全排列字符串。
例:ABB:ABB,BAB,BBA
代码:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<string> res;
void permutation(char* str, char *pBegin) {
if (*pBegin == '\0') {
res.push_back(str);
}
else {
for (char* pCh = pBegin; *pCh != '\0'; ++pCh) {
char temp = *pCh;
*pCh = *pBegin;
*pBegin = temp; //实现pBegin位置为pStr中的任一字符
permutation(str, pBegin + 1); //原pBegin的字符,可以在后续中出现
temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
}
}
}
int main() {
char str[] = "ABC";
permutation(str, str);
for (int i = 0; i < res.size(); i++)
cout << res[i] << endl;
system("pause");
}
面试题三
括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。
说明:解集不能包含重复的子集。
代码:
class Solution {
public:
void dfs(int n, int i, int j, string& res, vector<string>& result)
{
if (i > n || j > n || i < j) {
return;
}
if (i == n && j == n) {
result.push_back(res);
return;
}
res.push_back('(');
dfs(n, i + 1, j, res, result);
res.pop_back();
res.push_back(')');
dfs(n, i, j + 1, res, result);
res.pop_back();
}
vector<string> generateParenthesis(int n) {
string res;
vector<string> result;
dfs(n, 0, 0, res, result);
return result;
}
};