Problem: 1616. 分割两个字符串得到回文串
思路
尽可能多的匹配a的前缀和b的后缀,判断剩下区间内是否有存在回文。否则再重复上述过程,匹配b的前缀和a的后缀。
解题方法
-
使用双指针法:对于a的前缀、b的后缀的匹配,左指针从
a[0]
向右,右指针从b[n-1]
向左,尽可能多的(贪心)匹配相等的串。
-
结束后,左右指针所夹区间
[i:j]
分别对a和b串切片、判断回文。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 -
如果上述不构成回文,再对称判断a的前缀、b的后缀。
-
注意,在判断回文串的时候也传入双指针
i,j
,要考虑奇回文串和偶回文串两种情况。对于奇回文串,i==j
是回文成立条件;对于偶回文串,i=j+1
是回文成立条件(i到了j的恰好右边一处)。综上可以用i>=j
合并。
复杂度
- 时间复杂度:
O ( n ) O(n) O(n),在第一种a前缀、b后缀匹配时,只需要遍历a-prefix + b-suffix 的长度为n的区间。故为 O ( n ) O(n) O(n)
- 空间复杂度:
O ( 1 ) O(1) O(1),只需要两个指针i,j
C++(递归法)
//递归法
class Solution {
public:
bool IsPalindrome(string str,int i,int j) {
//考虑翻下来的情况
while (i < j && str[i] == str[j])
i++, j--;
return i>=j;
}
bool checkPalindromeFormation(string a, string b) {
//先检索一遍a的前缀与b的后缀的情况
int m = b.length();
//双指针法,i先遍历a,j从后遍历b
int i = 0, j = m - 1;
while (i < j && a[i] == b[j])
i++, j--;
if (IsPalindrome(a, i, j) || IsPalindrome(b, i, j))
return true;
//再检索一遍b的前缀和a的后缀的情况
i = 0, j = m - 1;
while (i < j && b[i] == a[j])
i++, j--;
if (IsPalindrome(a, i, j) || IsPalindrome(b, i, j))
return true;
return false;
}
};
Python
#递归法
class Solution:
#判断给定字符串str,[i:j+1]是否回文
def IsPalindrome(self,s:str,i:int,j:int)->bool:
while i<j and s[i]==s[j]:
i+=1
j-=1
#对于偶回文串——i=j+1;奇回文串 i==j,合并成i>=j
return i>=j
def checkPalindromeFormation(self, a: str, b: str) -> bool:
#尽可能多匹配首尾
n=len(a)
i,j=0,n-1
#考虑a的前缀和b的后缀
while i<j and a[i]==b[j]:
i+=1
j-=1
if self.IsPalindrome(a,i,j) or self.IsPalindrome(b,i,j):
return True
i,j=0,n-1
#考虑a的后缀和b的前缀
while i<j and b[i]==a[j]:
i+=1
j-=1
return self.IsPalindrome(a,i,j) or self.IsPalindrome(b,i,j)
C++(迭代)
//迭代法
class Solution {
public:
bool checkPalindromeFormation(string a, string b) {
//先检索一遍a的前缀与b的后缀的情况
int m = b.length();
//双指针法,i先遍历a,j从后遍历b
int i = 0, j = m - 1;
while (i < j && a[i]==b[j])
i++, j--;
//考虑翻下来的情况
int ii = i, jj = j;
if (b[i] == b[j]) {
while (i < j && b[i] == b[j])
i++, j--;
}
if (i == j || i - j == 1) return true;
//考虑翻上去
i = ii, j = jj;
if (a[i] == a[j]) {
while (i < j && a[i] == a[j])
i++, j--;
}
if (i == j || i-j == 1) return true;
//再检索一遍b的前缀和a的后缀的情况
i = 0,j=m-1;
while (i < j && b[i] == a[j])
i++, j--;
//考虑翻下来的情况x
ii = i, jj = j;
if (b[i] == b[j]) {
while (i < j && b[i] == b[j])
i++, j--;
}
if (i == j || i - j == 1) return true;
//考虑翻上去
i = ii, j = jj;
if (a[i] == a[j]) {
while (i < j && a[i] == a[j])
i++, j--;
}
if (i == j ||i-j == 1) return true;
return false;
}
};