文章目录
题目
标题和出处
标题:分割两个字符串得到回文串
难度
6 级
题目描述
要求
给定两个长度相同的字符串 a \texttt{a} a 和 b \texttt{b} b。选择一个下标,将两个字符串都在相同的下标 分割。由 a \texttt{a} a 可以得到两个字符串: a prefix \texttt{a}\texttt{prefix} aprefix 和 a suffix \texttt{a}\texttt{suffix} asuffix,满足 a = a prefix + a suffix \texttt{a} = \texttt{a}\texttt{prefix} + \texttt{a}\texttt{suffix} a=aprefix+asuffix。由 b \texttt{b} b 可以得到两个字符串 b prefix \texttt{b}\texttt{prefix} bprefix 和 b suffix \texttt{b}\texttt{suffix} bsuffix,满足 b = b prefix + b suffix \texttt{b} = \texttt{b}\texttt{prefix} + \texttt{b}\texttt{suffix} b=bprefix+bsuffix。判断 a prefix + b suffix \texttt{a}\texttt{prefix} + \texttt{b}\texttt{suffix} aprefix+bsuffix 或者 b prefix + a suffix \texttt{b}\texttt{prefix} + \texttt{a}\texttt{suffix} bprefix+asuffix 能否构成回文串。
当一个字符串 s \texttt{s} s 分割成 s prefix \texttt{s}\texttt{prefix} sprefix 和 s suffix \texttt{s}\texttt{suffix} ssuffix 时, s suffix \texttt{s}\texttt{suffix} ssuffix 或者 s prefix \texttt{s}\texttt{prefix} sprefix 可以为空。例如, s = "abc" \texttt{s} = \texttt{"abc"} s="abc",那么 "" + "abc" \texttt{""} + \texttt{"abc"} ""+"abc", "a" + "bc" \texttt{"a"} + \texttt{"bc"} "a"+"bc", "ab" + "c" \texttt{"ab"} + \texttt{"c"} "ab"+"c" 和 "abc" + "" \texttt{"abc"} + \texttt{""} "abc"+"" 都是可行的分割。
如果能构成回文串,返回 true \texttt{true} true,否则返回 false \texttt{false} false。
注意 x + y \texttt{x} + \texttt{y} x+y 表示字符串 x \texttt{x} x 和 y \texttt{y} y 连接后的结果。
示例
示例 1:
输入: a = "x", b = "y" \texttt{a = "x", b = "y"} a = "x", b = "y"
输出: true \texttt{true} true
解释:如果 a \texttt{a} a 或者 b \texttt{b} b 是回文串,那么答案一定为 true \texttt{true} true,因为可以如下分割:
a prefix = "" \texttt{a}\texttt{prefix} = \texttt{""} aprefix="", a suffix = "x" \texttt{a}\texttt{suffix} = \texttt{"x"} asuffix="x"
b prefix = "" \texttt{b}\texttt{prefix} = \texttt{""} bprefix="", b suffix = "y" \texttt{b}\texttt{suffix} = \texttt{"y"} bsuffix="y"
那么 a prefix + b suffix = "" + "y" = "y" \texttt{a}\texttt{prefix} + \texttt{b}\texttt{suffix} = \texttt{""} + \texttt{"y"} = \texttt{"y"} aprefix+bsuffix=""+"y"="y" 是回文串。
示例 2:
输入: a = "xbdef", b = "xecab" \texttt{a = "xbdef", b = "xecab"} a = "xbdef", b = "xecab"
输出: false \texttt{false} false
示例 3:
输入: a = "ulacfd", b = "jizalu" \texttt{a = "ulacfd", b = "jizalu"} a = "ulacfd", b = "jizalu"
输出: true \texttt{true} true
解释:在下标 3 \texttt{3} 3 处分割:
a prefix = "ula" \texttt{a}\texttt{prefix} = \texttt{"ula"} aprefix="ula", a suffix = "cfd" \texttt{a}\texttt{suffix} = \texttt{"cfd"} asuffix="cfd"
b prefix = "jiz" \texttt{b}\texttt{prefix} = \texttt{"jiz"} bprefix="jiz", b suffix = "alu" \texttt{b}\texttt{suffix} = \texttt{"alu"} bsuffix="alu"
那么 a prefix + b suffix = "ula" + "alu" = "ulaalu" \texttt{a}\texttt{prefix} + \texttt{b}\texttt{suffix} = \texttt{"ula"} + \texttt{"alu"} = \texttt{"ulaalu"} aprefix+bsuffix="ula"+"alu"="ulaalu" 是回文串。
数据范围
- 1 ≤ a.length, b.length ≤ 10 5 \texttt{1} \le \texttt{a.length, b.length} \le \texttt{10}^\texttt{5} 1≤a.length, b.length≤105
- a.length = b.length \texttt{a.length} = \texttt{b.length} a.length=b.length
- a \texttt{a} a 和 b \texttt{b} b 都只包含小写英语字母
解法
思路和算法
根据题目要求,将字符串分割成的两个子串中可以有一个子串为空。如果字符串 a a a 和 b b b 中至少有一个是回文串,则可以将 a a a 分割成 "" + a \text{``"} + a ""+a,将 b b b 分割成 "" + b \text{``"} + b ""+b, "" + a \text{``"} + a ""+a 和 "" + b \text{``"} + b ""+b 中至少有一个是回文串,因此一定存在构成回文串的分割方案,返回 true \text{true} true。
如果字符串 a a a 和 b b b 都不是回文串,则需要判断是否存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 或 b prefix + a suffix b_\textit{prefix} + a_\textit{suffix} bprefix+asuffix 是回文串。用 n n n 表示字符串 a a a 和 b b b 的长度,需要判断是否存在下标 i i i 使得 a [ 0 : i − 1 ] + b [ i : n − 1 ] a[0 : i - 1] + b[i : n - 1] a[0:i−1]+b[i:n−1] 是回文串,或下标 j j j 使得 b [ 0 : j − 1 ] + a [ j : n − 1 ] b[0 : j - 1] + a[j : n - 1] b[0:j−1]+a[j:n−1] 是回文串,其中 0 < i , j < n 0 < i, j < n 0<i,j<n, s [ start : end ] s[\textit{start} : \textit{end}] s[start:end] 表示字符串 s s s 的下标范围 [ start , end ] [\textit{start}, \textit{end}] [start,end] 中的子串。
判断是否存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 是回文串时,需要判断是否存在下标 i i i 使得 a [ 0 : i − 1 ] + b [ i : n − 1 ] a[0 : i - 1] + b[i : n - 1] a[0:i−1]+b[i:n−1] 是回文串。用 left \textit{left} left 和 right \textit{right} right 分别表示 a a a 和 b b b 的下标,初始时 left = 0 \textit{left} = 0 left=0, right = n − 1 \textit{right} = n - 1 right=n−1,执行如下操作。
-
当 left < right \textit{left} < \textit{right} left<right 时,每次比较 a [ left ] a[\textit{left}] a[left] 和 b [ right ] b[\textit{right}] b[right],如果 a [ left ] = b [ right ] a[\textit{left}] = b[\textit{right}] a[left]=b[right],则将 left \textit{left} left 向右移动一位,将 right \textit{right} right 向左移动一位,重复该操作直到 left ≥ right \textit{left} \ge \textit{right} left≥right 或 a [ left ] ≠ b [ right ] a[\textit{left}] \ne b[\textit{right}] a[left]=b[right]。
-
如果存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 是回文串,则应满足 a [ left : right ] a[\textit{left} : \textit{right}] a[left:right] 是回文串或 b [ left : right ] b[\textit{left} : \textit{right}] b[left:right] 是回文串。如果 a [ left : right ] a[\textit{left} : \textit{right}] a[left:right] 是回文串,则取分割下标 i = right + 1 i = \textit{right} + 1 i=right+1 即符合要求;如果 b [ left : right ] b[\textit{left} : \textit{right}] b[left:right] 是回文串,则取分割下标 j = left j = \textit{left} j=left 即符合要求。特别地,如果 left ≥ right \textit{left} \ge \textit{right} left≥right,则 a [ left : right ] a[\textit{left} : \textit{right}] a[left:right] 和 b [ left : right ] b[\textit{left} : \textit{right}] b[left:right] 都是回文串,此时取分割下标 i = right + 1 i = \textit{right} + 1 i=right+1 或 j = left j = \textit{left} j=left 皆符合要求。
使用同样的方法,可以判断是否存在 b prefix + a suffix b_\textit{prefix} + a_\textit{suffix} bprefix+asuffix 是回文串。
如果存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 是回文串或存在 b prefix + a suffix b_\textit{prefix} + a_\textit{suffix} bprefix+asuffix 是回文串,返回 true \text{true} true,否则返回 false \text{false} false。
证明
以判断是否存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 是回文串为例,上述做法的正确性证明如下。
上述做法中,左右指针 left \textit{left} left 和 right \textit{right} right 始终满足 left + right = n − 1 \textit{left} + \textit{right} = n - 1 left+right=n−1。当 left < right \textit{left} < \textit{right} left<right 且 a [ left ] ≠ b [ right ] a[\textit{left}] \ne b[\textit{right}] a[left]=b[right] 时,分别取分割下标为 left \textit{left} left 和 right + 1 \textit{right} + 1 right+1 判断是否存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 是回文串,如果存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 是回文串,则可以构成回文串。
如果在下标范围 [ left + 1 , right ] [\textit{left} + 1, \textit{right}] [left+1,right] 中取分割下标,则由于 a [ left ] ≠ b [ right ] a[\textit{left}] \ne b[\textit{right}] a[left]=b[right],因此无论取哪个分割下标, a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 的下标 left \textit{left} left 和 right \textit{right} right 的字符都不相同,因此 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 不是回文串。
如果分割下标小于 left \textit{left} left 或大于 right + 1 \textit{right} + 1 right+1,例如取 left ′ < left \textit{left}' < \textit{left} left′<left 和 right ′ > right \textit{right}' > \textit{right} right′>right 且 left ′ + right ′ = n − 1 \textit{left}' + \textit{right}' = n - 1 left′+right′=n−1,则当分割下标为 left ′ \textit{left}' left′ 或 right ′ + 1 \textit{right}' + 1 right′+1 时,应满足 a [ left ′ : right ′ ] a[\textit{left}' : \textit{right}'] a[left′:right′] 是回文串或 b [ left ′ : right ′ ] b[\textit{left}' : \textit{right}'] b[left′:right′] 是回文串。由于下标范围 [ left ′ , right ′ ] [\textit{left}', \textit{right}'] [left′,right′] 的子串长度大于下标范围 [ left , right ] [\textit{left}, \textit{right}] [left,right] 的子串长度,因此下标范围 [ left ′ , right ′ ] [\textit{left}', \textit{right}'] [left′,right′] 的子串是回文串的可能性更低。如果取分割下标 left \textit{left} left 和 right + 1 \textit{right} + 1 right+1 不能得到回文串,则取分割下标 left ′ \textit{left}' left′ 和 right ′ + 1 \textit{right}' + 1 right′+1 更不能得到回文串。因此取分割下标 left \textit{left} left 和 right + 1 \textit{right} + 1 right+1 是最优方案。
代码
java
class Solution {
public boolean checkPalindromeFormation(String a, String b) {
if (isPalindrome(a) || isPalindrome(b)) {
return true;
}
return checkPrefixSuffix(a, b) || checkPrefixSuffix(b, a);
}
public boolean isPalindrome(String s) {
return isPalindrome(s, 0, s.length() - 1);
}
public boolean isPalindrome(String s, int start, int end) {
int left = start, right = end;
while (left < right) {
if (s.charAt(left) != s.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
public boolean checkPrefixSuffix(String a, String b) {
int left = 0, right = b.length() - 1;
while (left < right && a.charAt(left) == b.charAt(right)) {
left++;
right--;
}
return isPalindrome(a, left, right) || isPalindrome(b, left, right);
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 a a a 和 b b b 的长度。需要使用双指针遍历两个字符串有限次。
-
空间复杂度: O ( 1 ) O(1) O(1)。