文章摘要:
- 本文解析LeetCode题目《字母大小写全排列》,要求生成给定字符串所有字母大小写组合。通过决策树模型展示递归过程:遍历字符串,遇到字母时分别添加大小写形式,数字则直接添加。使用回溯法维护全局变量ret(结果集)和path(当前路径),递归出口为遍历完字符串时保存结果。提供两种Java实现:版本一显式处理大小写转换,版本二封装转换函数。两种方案均通过回溯恢复现场确保状态正确,最终返回所有可能组合。
文章目录
- 一、题目解析
- [二、算法原理 + 代码实现](#二、算法原理 + 代码实现)
一、题目解析

题目会给出一个字符串,让我们将字符串里的字母转换大小写,找出所有的组合。
例如示例 1 给出的字符串 s = "a1b2",我们需要返回 [ "a1b2", "a1B2", "A1b2", "A1B2" ]。
二、算法原理 + 代码实现
决策树
我们按照暴搜的普遍思路:依次枚举画出决策树。
根据示例 1:

从左往右遍历字符串,遇到字母就选择添加大写还是小写,遇到数字就直接添加,枚举每一种情况。
决策树如下:

全局变量
这里依然是两个全局变量:ret 记录结果、path 记录路径。
dfs 函数
函数头
由于我们是遍历字符串,要将 s 作为参数,而且是通过递归遍历的,因此需要知道下标 pos。
Java
dfs(String s, int pos);
函数体
考虑每一次递归所做的事情,那就是遇到字母就考虑大小写,而遇到数字就无需考虑直接添加。
Java
if (字母的判定条件) {
// 先添加小写
// 再添加大写
} else {
// 添加数字
}
注意,每一次添加完递归回来后都要考虑恢复现场。
除了依次添加大小写,也可以直接通过一个函数完成大小写的转换:
Java
if (字母的判定条件) {
// 转换后添加字母
}
// 添加数字
细节问题
回溯
回溯时的恢复现场操作是将 path 的最后元素删掉。
剪枝
本题是穷举了所有情况,因此不涉及剪枝操作。
递归出口
当遍历到字符串 s 的最后字符就需要更新结果了,然后返回即可。
代码实现
版本一
Java
class Solution {
List<String> ret;
StringBuilder path;
public List<String> letterCasePermutation(String s) {
ret = new ArrayList<>();
path = new StringBuilder();
dfs(s, 0);
return ret;
}
private void dfs(String s, int pos) {
// 递归出口
if (pos == s.length()) {
ret.add(path.toString());
return;
}
char ch = s.charAt(pos);
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
// 是字母,需要转换大小写
// 添加小写字母
if (ch >= 'A' && ch <= 'Z') path.append(ch += 32);
else path.append(ch);
dfs(s, pos + 1);
path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
// 添加大写字母
if (ch >= 'a' && ch <= 'z') path.append(ch -= 32);
else path.append(ch);
dfs(s, pos + 1);
path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
} else {
// 是数字,直接添加
path.append(ch);
dfs(s, pos + 1);
path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
}
}
}
版本二
Java
class Solution {
List<String> ret;
StringBuilder path;
public List<String> letterCasePermutation(String s) {
ret = new ArrayList<>();
path = new StringBuilder();
dfs(s, 0);
return ret;
}
private void dfs(String s, int pos) {
// 递归出口
if (pos == s.length()) {
ret.add(path.toString());
return;
}
char ch = s.charAt(pos);
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
// 是字母,需要转换大小写
path.append(deal(ch));
dfs(s, pos + 1);
path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
}
// 是数字,不用转换直接添加
path.append(ch);
dfs(s, pos + 1);
path.deleteCharAt(path.length() - 1); // 回溯时恢复现场
}
private char deal(char ch) {
if (ch >= 'a' && ch <= 'z') return ch -= 32;
else return ch += 32;
}
}
文章到这里就告一段落啦,若有错误请尽管指出~
完