题目的要求是给定一个字符串,该字符串中只包含数字和字母,要求对字符串的字母进行大小写切换,输出所有可能的结果。
例如给定字符串a1b2要求输出a1b2、a1B2、A1b2、A1B2。
思路:这题看上去就是碰到字母转大小写以后保存,但是处理起来不是很轻松。看到leetcode上标记为backtracking,故而学习一下关于backtracking的知识。
参考了一下https://blog.csdn.net/ffmpeg4976/article/details/45007439 这篇博客,讲的比较清楚。
他引用了严奶奶的数据结构一书的一段话:在程序设计中,有相当一类求一组解,或求全部解或求最优解的问题,例如读者熟悉的八皇后问题,不是根据某种特定的计算法则,而是利用试探和回溯的搜索技术求解。回溯法也是设计递归过程的一种重要方法,它的求解过程实质上是一个先序遍历一棵"状态树"的过程,只是这棵树不是遍历前预先建立的,而是隐含在遍历过程中。
状态数的叶子节点代表解空间的每一个解。
状态树的递归其实就是采用深度优先搜索。
给出了一个公式:
void dfs(层数)
{
if(condition) //递归的终止条件为层数达到了最底层,即叶子节点所在层。
{
输出状态树的叶子
}
else
{
处理左子树
dfs(层数+1)
处理右子树
dfs(层数+1)
}
}
那么对于这道题而言,我们需要遍历这个字符串构成的状态树。
在遍历状态树的过程中,我们的处理左子树和处理右子树实质上就是对小写字母和大写字母两种情形的处理。
这样一想,不难得到以下的回溯算法的代码:
class Solution {
public:
vector<string> letterCasePermutation(string S) {
vector<string> vec;
dfs(0, vec, S);
return vec;
}
void dfs(int level, vector<string> &vec, string s)
{
if (level == s.length()) //到达了叶子的层数,此处为字符串的长度。
{
vec.push_back(s); //保存叶子节点的字符串
return;
}
else
{
dfs(level+1, vec, s); //“左子树”的处理为空,认为当前的字符就代表一个状态树的左子树if (isalpha(s[level])) //右子树的处理,如果左子树的字母为大写则换成小写,否则换成大写。
{
s[level] = s[level]==toupper(s[level])?tolower(s[level]):toupper(s[level]);
dfs(level+1, vec, s);
}
}
}
};