131.分割回文串
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
示例 1: 输入:s = “aab” 输出:[[“a”,”a”,”b”],[“aa”,”b”]] 示例 2: 输入:s = “a” 输出:[[“a”]]
提示: 1 <= s.length <= 16 s 仅由小写英文字母组成
解法1
- 思路:难点是考虑这个字符串要怎么截取:利用循环i和current,先让i为current,保证被current-1选过的无法再次选取。再通过循环i让每次循环能够截取的长度增大,这样就能得到不同长度的字符串,同时也能保证在同一个集合中题目给出的字符串中每个字符都能出现。并且为了让性能提升需要剪枝,先判断是否为回文串,不是则直接剪枝
- 流程图
static List<List<String>> res;
public static List<List<String>> partition2(String s) {
res = new ArrayList<>();
char[] chars = s.toCharArray();
Deque<String> perm = new ArrayDeque<>();
dfs(chars, 0, perm);
return res;
}
/**
* 怎么让截取的长度不一样?
* 利用i和current,随着循环层数的增加使截取长度的增加。current的增加只是使得开始截取的位置改变
* @param chars
* @param current
* @param perm
*/
private static void dfs(char[] chars, int current, Deque<String> perm) {
int n = chars.length;
if (current == n) {
res.add(new ArrayList<>(perm));
return;
}
for (int i = current; i < n; i++) {
if (!checkPalindrome(chars, current, i)) {
continue;
}
//这个方法里面current就是从哪里开始截取,i + 1 - current是要截取的长度
perm.addLast(new String(chars, current, i + 1 - current));
//System.out.println("begin=="+perm);
dfs(chars,i+1,perm);
perm.removeLast();
//System.out.println("end=="+perm);
}
}
/**
* 判断是否为回文串,因为截取字符串是消耗性能的,所以就要传下标判断
* @param chars
* @param left
* @param right
* @return
*/
private static boolean checkPalindrome(char[] chars, int left, int right) {
while (left < right) {
if (chars[left] != chars[right]) {
return false;
}
left++;
right--;
}
return true;
}
解法2
思路:回溯的优化,利用动态规划得到所有字串是否为回文。
暂时还没有看懂,刷一遍动态规划后再回来写思路
static List<List<String>> res;
public static List<List<String>> partition3(String s) {
int len = s.length();
res = new ArrayList<>();
char[] chars = s.toCharArray();
boolean[][] dp = new boolean[len][len];
for (int right = 0; right < len; right++) {
for (int left = 0; left <= right; left++) {
if (chars[left] == chars[right] && (right - left <= 2 || dp[left + 1][right - 1])) {
dp[left][right] = true;
}
}
}
Deque<String> perm = new ArrayDeque<>();
dfs2(s, 0, perm, len,dp);
return res;
}
private static void dfs2(String s, int current, Deque<String> perm, int len, boolean[][] dp) {
if (current == len) {
res.add(new ArrayList<>(perm));
return;
}
for (int i = current; i <len ; i++) {
if (dp[current][i]) {
perm.addLast(s.substring(current, i + 1));
dfs2(s, i + 1, perm, len, dp);
perm.removeLast();
}
}
}
93.复原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 地址。 给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 ‘.’ 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
示例 1: 输入:s = “25525511135” 输出:[“255.255.11.135”,”255.255.111.35”]
示例 2: 输入:s = “0000” 输出:[“0.0.0.0”]
示例 3: 输入:s = “101023” 输出:[“1.0.10.23”,”1.0.102.3”,”10.1.0.23”,”10.10.2.3”,”101.0.2.3”]
提示: 1 <= s.length <= 20 s 仅由数字组成
思路:自己写的代码,思路难免会有点乱。截取字符串的方式与分割回文串解法1相同,都是用字符串的substring方法或者是用new String()中的构造方法来截取。同时这题要用剪枝,如果这个字符串长度大于2,首位不能是0或者这个字符串不能超过4位且小于255。其实做了分割回文串这题就很好做了。
static List<String> res;
public static List<String> restoreIpAddresses(String s) {
res = new ArrayList<>();
List<String> perm = new ArrayList<>();
dfs(s, 0, perm);
return res;
}
private static void dfs(String s, int current, List<String> perm) {
int len = s.length();
if (current == len) {
if (perm.size() == 4) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < perm.size(); i++) {
sb.append(perm.get(i));
if (i != perm.size() - 1) {
sb.append(".");
}
}
res.add(sb.toString());
return;
}
return;
}
for (int i = current; i < len; i++) {
String substring = s.substring(current, i + 1);
if (substring.length() > 4) {
return;
}
if (i > current && (substring.charAt(0) == '0' || Integer.parseInt(substring) > 255)) {
continue;
}
if (perm.size() == 4) {
return;
}
perm.add(substring);
System.out.println("begin===" + perm);
dfs(s, i + 1, perm);
perm.remove(perm.size() - 1);
System.out.println("end==="+perm);
}
}