电话号码的字母组合
题目
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
力扣链接
思路
返回输入数字字符串对应的字母组合。
字母组合的字母数就等于输入的数字的字符数。
我们先将数字与字母的对应关系,写成一个字符串数组,方便下面操作。
String[] strings = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
采用回溯的思路,把结构想象成一棵树,那么取第一个数字对用的字符是在第一层,取第二个就在第二层,以此类推。
反映在代码中就是在第几层for循环中。
那么我们通过把数字字符串转换成整型,找到对应的字符串,然后进行组合。
代码
List<String> result = new ArrayList<>();
public List<String> letterCombinations(String digits) {
if (digits == null || digits.length() == 0){
return result;
}
String[] strings = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
backtracking(digits, strings, 0);
return result;
}
StringBuilder stringBuilder = new StringBuilder();
public void backtracking(String digits, String[] strings, int num) {
if (num == digits.length()) {
result.add(stringBuilder.toString());
return;
}
String str = strings[digits.charAt(num) - '0']; // 数字对应的字符串
for (int i = 0; i < str.length(); i++) {
stringBuilder.append(str.charAt(i));
backtracking(digits, strings, num + 1);
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
}
切割回文子串
思路
回溯三部曲:
- 递归的参数值
一维数组 path, 用来放已经回文的子串。这里需要经过判断。
需要startIndex, 因为切割是不能重复的,需要startIndex来让深层的for循环,移动切割位置。 - 终止条件
一串字符,切割到最后一位的时候终止。 - 单层循环逻辑
单层循环的时候需要判断是不是回文子串,不是回文子串就直接跳过一次for循环,该不是回文子串的内容也就不会加入到path中。 - 判断回文子串
写一个for循环,判断开头和末尾是否相等即可。
代码
List<List<String>> res = new ArrayList<>();
Deque<String> path = new LinkedList<>();
public List<List<String>> partiton(String s) {
backtracking(s, 0);
return res;
}
public void backtracking(String s, int StartIndex) {
if (StartIndex >= s.length()) {
res.add(new ArrayList<>(path));
return;
}
for (int i = StartIndex; i < s.length(); i++) {
if (isPalindrome(s, StartIndex, i)) {
String str = s.substring(StartIndex, i + 1);
path.addLast(str);
}else {
continue;
}
backtracking(s, i + 1);
path.removeLast();
}
}
public boolean isPalindrome(String s, int StartIndex, int end) {
for (int i = StartIndex, j = end; i < j; i++, j--) {
if (s.charAt(i) != s.charAt(j)) {
return false;
}
}
return true;
}
复原IP地址
题目
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。
例如:“0.1.2.201” 和 “192.168.1.1” 是 有效的 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “192.168@1.1” 是 无效的 IP 地址。
思路
- 递归参数
分割IP地址,不能重复分割,所以需要startIndex
同时还需要一个参数pointNum记录加入的逗点数量。
public void
- 递归终止条件
对于IP地址,切割四次就是有三个逗点的时候说明应该结束了。此时还需要判断一下第四段是否合法,如果合法的话,就加入结果集。 - 单层搜索逻辑
使用startIndex区分切割,然后剪枝掉无效的分支。
子集问题
问题 Leet78
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
代码
public class subsetsClass {
static List<List<Integer>> result = new ArrayList<>();
static Deque<Integer> path = new LinkedList<>();
public static List<List<Integer>> subsets(int[] nums) {
if (nums.length == 0) {
result.add(new ArrayList<>());
return result;
}
backTracking(nums, 0);
return result;
}
public static void backTracking(int[] nums, int startIndex) {
result.add(new ArrayList<>(path));
if (startIndex >= nums.length) {
return;
}
for (int i = startIndex; i < nums.length; i++) {
path.add(nums[i]);
backTracking(nums, i + 1);
path.removeLast();
}
}
public static void main(String[] args) {
int[] nums = {1, 2, 2};
List<List<Integer>> res = new ArrayList<>();
res = subsets(nums);
System.out.println(res);
}
}
子集问题II
问题 Leet90
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
思路
这道题与78的区别在于,给的集合中有重复的元素,但是解集要求不能有重复的子集。
去重的思路就是使用一个used数组,表名哪一个元素取过了。通过这个标签,就可以得到不重复的子集。
代码
public class subsetsWithDupClass {
List<List<Integer>> result = new ArrayList<>();
Deque<Integer> path = new LinkedList<>();
boolean[] used;
public List<List<Integer>> subsetsWithDup(int[] nums) {
if (nums.length == 0) {
result.add(new ArrayList<>());
return result;
}
Arrays.sort(nums); //去重要记得排序
used = new boolean[nums.length];
Helper(nums, 0);
return result;
}
public void Helper(int[] nums, int startIndex) {
result.add(new ArrayList<>(path));
if (startIndex >= nums.length) {
return;
}
for (int i = startIndex; i < nums.length; i++) {
if (i > 0 && nums[i] == nums[i - 1] && !used[i-1]) { //与前一项相等且前一项的used是1的说明是同一层的,要去重
continue;
}
path.add(nums[i]);
used[i] = true;
Helper(nums, i + 1);
used[i] = false;
path.removeLast();
}
}
}