复原IP地址
给定一个只包含数字的字符串,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 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 地址。
示例 1:
输入:s = “25525511135”
输出:[“255.255.11.135”,“255.255.111.35”]
示例 2:
输入:s = “0000”
输出:[“0.0.0.0”]
示例 3:
输入:s = “1111”
输出:[“1.1.1.1”]
示例 4:
输入:s = “010010”
输出:[“0.10.0.10”,“0.100.1.0”]
示例 5:
输入:s = “101023”
输出:[“1.0.10.23”,“1.0.102.3”,“10.1.0.23”,“10.10.2.3”,“101.0.2.3”]
回溯法
class Solution {
private char[] charList;
private List<String> result = new ArrayList<String>();
private int[] segments = new int[4];
private int len = 0;
public List<String> restoreIpAddresses(String s) {
charList = s.toCharArray();
len = charList.length;
backtrack(0, 0);
return result;
}
private void backtrack(int start, int n) {
if (n == 4) {
if (start == len) {
StringBuilder sb = new StringBuilder();
sb.append(segments[0]);
for (int i = 1; i < 4; i++)
sb.append(".").append(segments[i]);
result.add(sb.toString());
}
return;
}
if (start == len)
return;
if (charList[start] == '0') {
segments[n] = 0;
backtrack(start + 1, n + 1);
} else {
int num = 0;
for (int i = start; i < len; i++) {
num = 10 * num + (charList[i] - '0');
if (num > 0 && num < 256) {
segments[n] = num;
backtrack(i + 1, n + 1);
} else {
break;
}
}
}
}
}
子集1
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
迭代法
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
results.add(new ArrayList<Integer>());
for (int n : nums) {
int size = results.size();
for (int i = 0; i < size; i++) {
List<Integer> cur = new ArrayList<>(results.get(i));
cur.add(n);
results.add(cur);
}
}
return results;
}
}
回溯法
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
backtrack(results, new ArrayList<Integer>(), 0, nums);
return results;
}
private void backtrack(List<List<Integer>> results, List<Integer> subset, int start, int[] nums) {
results.add(new ArrayList<>(subset));
for (int i = start; i < nums.length; i++) {
subset.add(nums[i]);
backtrack(results, subset, i + 1, nums);
subset.remove(subset.size() - 1);
}
}
}
子集2
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
回溯法
class Solution {
private int len;
public List<List<Integer>> subsetsWithDup(int[] nums) {
this.len = nums.length;
Arrays.sort(nums);
List<List<Integer>> result = new ArrayList<>();
backtrack(nums, result, new ArrayList<>(), 0);
return result;
}
private void backtrack(int[] ns, List<List<Integer>> res, List<Integer> comb, int start) {
res.add(new ArrayList<>(comb));
for (int i = start; i < len; i++) {
if (i > start && ns[i] == ns[i - 1])
continue;
comb.add(ns[i]);
backtrack(ns, res, comb, i + 1);
comb.remove(comb.size() - 1);
}
}
}
迭代法
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
result.add(new ArrayList<>());
Arrays.sort(nums);
int start = 1;
for (int i = 0; i < nums.length; i++) {
List<List<Integer>> cur_result = new ArrayList<>();
for (int j = 0; j < result.size(); j++) {
if (j < start && i > 0 && nums[i] == nums[i - 1])
continue;
List<Integer> combine = new ArrayList<>(result.get(j));
combine.add(nums[i]);
cur_result.add(combine);
}
start = result.size();
result.addAll(cur_result);
}
return result;
}
}
组合
给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
回溯法
class Solution {
private int count = 0;
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> results = new ArrayList<>();
backtrack(results, new ArrayList<Integer>(), 1, n, k);
return results;
}
private void backtrack(List<List<Integer>> results, List<Integer> subset, int start, int n, int k) {
if (subset.size() + n - start + 1 < k)
return;
if (subset.size() == k) {
results.add(new ArrayList<>(subset));
return;
}
for (int i = start; i <= n; i++) {
subset.add(i);
backtrack(results, subset, i + 1, n, k);
subset.remove(subset.size() - 1);
}
}
}
电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]
示例 2:
输入:digits = “”
输出:[]
示例 3:
输入:digits = “2”
输出:[“a”,“b”,“c”]
回溯法
class Solution {
public List<String> letterCombinations(String digits) {
List<String> result = new ArrayList<>();
if (digits.length() < 1) {
return result;
}
String[] letterMap = { "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
backtrack(result, letterMap, digits, 0, new StringBuffer());
return result;
}
private void backtrack(List<String> result, String[] letterMap, String digits, int index, StringBuffer curString) {
if (index == digits.length()) {
result.add(curString.toString());
} else {
char curLetter = digits.charAt(index);
String letters = letterMap[curLetter - '2'];
for (int i = 0; i < letters.length(); i++) {
char letter = letters.charAt(i);
curString.append(letter);
backtrack(result, letterMap, digits, index+1, curString);
curString.deleteCharAt(index);
}
}
}
}
二进制手表
二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。
例如,下面的二进制手表读取 “3:25” 。
给你一个整数 turnedOn ,表示当前亮着的 LED 的数量,返回二进制手表可以表示的所有可能时间。你可以 按任意顺序 返回答案。
小时不会以零开头:
- 例如,“01:00” 是无效的时间,正确的写法应该是 “1:00” 。
分钟必须由两位数组成,可能会以零开头:
- 例如,“10:2” 是无效的时间,正确的写法应该是 “10:02” 。
示例 1:
输入:turnedOn = 1
输出:[“0:01”,“0:02”,“0:04”,“0:08”,“0:16”,“0:32”,“1:00”,“2:00”,“4:00”,“8:00”]
示例 2:
输入:turnedOn = 9
输出:[]
回溯法
class Solution {
private boolean[] used = new boolean[10];
public List<String> readBinaryWatch(int turnedOn) {
List<String> result = new ArrayList<>();
if (turnedOn > 8 || turnedOn < 0)
return result;
backtrack(result, 0, 0, turnedOn);
return result;
}
private void backtrack(List<String> result, int start, int cur, int num) {
int minute = 0x3f & cur;
int hour = 0xf & (cur >> 6);
if (minute > 59 || hour > 11)
return;
if (num == 0) {
StringBuilder sb = new StringBuilder();
sb.append(hour).append(':');
if (minute < 10)
sb.append('0');
sb.append(minute);
result.add(sb.toString());
return;
}
for (int i = start; i < 10; i++) {
if (used[i])
continue;
used[i] = true;
backtrack(result, i + 1, cur | (1 << i), num - 1);
used[i] = false;
}
}
}
哈希表存储+组合
class Solution {
public List<String> readBinaryWatch(int turnedOn) {
List<String> result = new ArrayList<>();
if (turnedOn > 8 || turnedOn < 0)
return result;
Map<Integer, List<Integer>> minuteMap = new HashMap<>();
Map<Integer, List<Integer>> hourMap = new HashMap<>();
for (int i = 0; i < 60; i++) {
minuteMap.put(i, new ArrayList<Integer>());
if (i < 12)
hourMap.put(i, new ArrayList<Integer>());
}
for (int i = 0; i < 60; i++) {
int count = Integer.bitCount(i);
minuteMap.get(count).add(i);
if (i < 12)
hourMap.get(count).add(i);
}
for (int i = 0; i <= turnedOn; i++) {
List<Integer> minutes = minuteMap.get(turnedOn - i), hours = hourMap.get(i);
for (int h : hours) {
for (int m : minutes) {
StringBuilder sb = new StringBuilder();
sb.append(h).append(':');
if (m < 10)
sb.append('0');
sb.append(m);
result.add(sb.toString());
}
}
}
return result;
}
}