文章目录
1616. 分割两个字符串得到回文串
难度中等57
给你两个字符串 a
和 b
,它们长度相同。请你选择一个下标,将两个字符串都在 相同的下标 分割开。由 a
可以得到两个字符串: aprefix
和 asuffix
,满足 a = aprefix + asuffix
,同理,由 b
可以得到两个字符串 bprefix
和 bsuffix
,满足 b = bprefix + bsuffix
。请你判断 aprefix + bsuffix
或者 bprefix + asuffix
能否构成回文串。
当你将一个字符串 s
分割成 sprefix
和 ssuffix
时, ssuffix
或者 sprefix
可以为空。比方说, s = "abc"
那么 "" + "abc"
, "a" + "bc"
, "ab" + "c"
和 "abc" + ""
都是合法分割。
如果 能构成回文字符串 ,那么请返回 true
,否则返回 false
。
注意, x + y
表示连接字符串 x
和 y
。
示例 1:
输入:a = "x", b = "y"
输出:true
解释:如果 a 或者 b 是回文串,那么答案一定为 true ,因为你可以如下分割:
aprefix = "", asuffix = "x"
bprefix = "", bsuffix = "y"
那么 aprefix + bsuffix = "" + "y" = "y" 是回文串。
示例 2:
输入:a = "abdef", b = "fecab"
输出:true
示例 3:
输入:a = "ulacfd", b = "jizalu"
输出:true
解释:在下标为 3 处分割:
aprefix = "ula", asuffix = "cfd"
bprefix = "jiz", bsuffix = "alu"
那么 aprefix + bsuffix = "ula" + "alu" = "ulaalu" 是回文串。
提示:
1 <= a.length, b.length <= 105
a.length == b.length
a
和b
都只包含小写英文字母
暴力(超时)
class Solution {
public boolean checkPalindromeFormation(String a, String b) {
for(int i = 0; i < a.length(); i++){
if(check(a,b,i)) return true;
}
return false;
}
public boolean check(String a, String b, int idx){
String str1 = a.substring(0, idx) + b.substring(idx);
String str2 = b.substring(0, idx) + a.substring(idx);
if(isrev(str1) || isrev(str2)) return true;
else return false;
}
public boolean isrev(String s){
int l = 0, r = s.length()-1;
while(l < r){
if(s.charAt(l) != s.charAt(r)) return false;
l++; r--;
}
return true;
}
}
相向双指针优化
相向双指针求出前后缀最长匹配串, 然后判断a或b中剩余部分是否为回文串
class Solution {
// apre + bsuf 可以分为两种: 长为m的a前缀 + a\b中间是回文串 + 长为m的b前缀
// 相向双指针求出前后缀最长匹配串, 然后判断a或b中剩余部分是否为回文串
public boolean checkPalindromeFormation(String a, String b) {
return check(a, b) || check(b, a);
}
// 如果 a_prefix + b_suffix 可以构成回文串则返回 true,否则返回 false
public boolean check(String a, String b){
int i = 0, j = a.length() - 1;
while(i < j && a.charAt(i) == b.charAt(j)){// 前后缀尽量匹配
i++; j--;
}
return isPalindrome(a, i, j)|| isPalindrome(b, i, j);
}
// 如果从 s[i] 到 s[j] 是回文串则返回 true,否则返回 false
public boolean isPalindrome(String s, int i, int j){
while(i < j && s.charAt(i) == s.charAt(j)){
++i; --j;
}
return i >= j;
}
}
法二:中心扩展法(题解:Ikaruga)
https://leetcode.cn/problems/palindromic-substrings/solution/palindromic-substrings-by-ikaruga/
题解:https://leetcode.cn/problems/split-two-strings-to-make-palindrome/solution/split-two-strings-to-make-palindrome-by-ikaruga/
- 题目给出的字符串长度固定,可以直接使用 中心扩展法 检测
- 由中心向两侧分别检测字符串 a 和 b
- 即【前 a 后 a】和【前 b 后 b】
- 不断扩展,直到字符不相同,中间部分都是回文串
- 结合下图观看,同时检测两条字符串,我们只关心回文更长的那串,具体是哪条更长不重要
- 当不符合回文串时,有一次机会将两个字符串拼接一下
- 继续扩展检测,这次检测拼接后的字符串
- 即【前 a 后 b】和【前 b 后 a】
- 结合下图观看,因为拼接的字符串既有 a 也有 b,所以之前更长的是哪串都不影响
- 当再次结束检测时
- 如字符再次不相同,则是匹配失败
- 如全部匹配,则
left
应该为 -1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hRpXFYYn-1679098921481)(https://pic.leetcode-cn.com/1602390786-XfOHyx-%E5%9B%BE%E7%89%87.png)]
- 如图所示,第一次检测时,字符串 a 的中心并没有回文串,而字符串 b 有一段合法回文串
- 第二次检测时,【前 a 后 b】通过测试
- 最终,【前 a 后 b】和 b 的中心子串组合起来,就是拼接后的回文串(所有有底色的字符)
class Solution {
public boolean checkPalindromeFormation(String a, String b) {
int left = a.length()/2 - 1;
left = Math.min(check(a, a, left), check(b, b, left));
left = Math.min(check(a, b, left), check(b, a, left));
return left == -1;
}
int check(String str1, String str2, int left){
int right = str1.length() - 1 - left;
while(left >= 0 && str1.charAt(left) == str2.charAt(right)){
left--; right++;
}
return left;
}
}
eft;
while(left >= 0 && str1.charAt(left) == str2.charAt(right)){
left–; right++;
}
return left;
}
}