问题描述
思路分析
首先这个题目要求的是全排列。那么就是无可避免地使用回溯法。这里建议对回溯的思想和经典的模板要熟悉。
那么这道题我其实并没有用求排列的方式,而是使用的组合。
二者的区别是:
1. 排列需要用used数组来标记该遍历的位置是否加入到结果集了;
2. 组合则不需要,因为下次递归的起始下标从当前遍历的位置的下一个位置开始。
二者的联系是:排列是从一个数组(n个元素)中选择1、2、3…n个数字的组合。
这道题为什么我没有采用排列的思路呢?因为我们无法确定递归终止的条件,因为结果中的元素并不允许位置上的变化。
如果求组合,使用一个for循环指定每次需要选择的组合数,每次选择i个数转化大小写(组合过程)即可。
注意几点:
- 跳过非字符的位置;
- 递归的深度和遍历的下标并不是相等的,要分别记录(depth和idx)。
code
class Solution {
public List<String> letterCasePermutation(String s) {
List<String> res = new ArrayList();
if (s.length() == 0) return res;
res.add(s);
char[] chs = s.toCharArray();
int count = 0;
for (int i = 0; i < chs.length; i++) {
if (!isNum(chs[i])) count++;
}
if (count == 0) return res;
for (int j = 1; j <= count; j++) combine(chs, j, 0, 0 , res);
return res;
}
// 求组合数的模板
public void combine(char[] chs, int j, int depth, int idx, List<String> res) {
if (depth == j) {
res.add(new String(chs));
return;
}
for (int i = idx; i < chs.length; i++) {
char ch = chs[i];
if (isNum(ch)) continue;
exchange(chs, i);
combine(chs, j, depth+1,i+1, res);
exchange(chs, i);
}
}
public boolean isNum(char ch) {
return ch <= '9' && ch >= '0';
}
// 交换大小写
public void exchange(char[] chs, int i) {
if (chs[i] >= 97) chs[i] = (char)(chs[i] - 32);
else chs[i] = (char)(chs[i] + 32);
}
}