双指针题目:分割两个字符串得到回文串

文章目录

题目

标题和出处

标题:分割两个字符串得到回文串

出处:1616. 分割两个字符串得到回文串

难度

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,执行如下操作。

  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]。

  2. 如果存在 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)。

相关推荐
李日灐5 小时前
【优选算法1】双指针经典算法题
数据结构·c++·后端·算法·刷题·双指针
仟濹2 天前
【算法打卡day22(2026-03-14 周六)今日算法or技巧:双指针 & 链表】9个题
数据结构·算法·链表·双指针
锅包一切1 个月前
PART2 双指针
c++·算法·leetcode·力扣·双指针
脏脏a1 个月前
【优选算法・双指针】以 O (n) 复杂度重构数组操作:从暴力遍历到线性高效的范式跃迁
算法·leetcode·双指针·牛客·优选算法
识君啊1 个月前
Java双指针 - 附LeetCode 经典题解
java·算法·leetcode·java基础·双指针
伟大的车尔尼1 个月前
双指针题目:下一个排列
双指针
小冻梨6661 个月前
ABC444 C - Atcoder Riko题解
c++·算法·双指针
伟大的车尔尼1 个月前
双指针题目:压缩字符串
双指针
hnjzsyjyj1 个月前
洛谷 P13270:【模板】最小表示法 ← 双指针 + 解环成链
字符串·双指针·解环成链