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

文章目录

题目

标题和出处

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

出处: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 a0 : i - 1 + bi : n - 1 a0:i−1+bi:n−1 是回文串,或下标 j j j 使得 b 0 : j − 1 + a j : n − 1 b0 : j - 1 + aj : n - 1 b0:j−1+aj:n−1 是回文串,其中 0 < i , j < n 0 < i, j < n 0<i,j<n, s start : end s\\textit{start} : \\textit{end} sstart: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 a0 : i - 1 + bi : n - 1 a0:i−1+bi: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} aleft 和 b right b\\textit{right} bright,如果 a left = b right a\\textit{left} = b\\textit{right} aleft=bright,则将 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} aleft=bright

  2. 如果存在 a prefix + b suffix a_\textit{prefix} + b_\textit{suffix} aprefix+bsuffix 是回文串,则应满足 a left : right a\\textit{left} : \\textit{right} aleft:right 是回文串或 b left : right b\\textit{left} : \\textit{right} bleft:right 是回文串。如果 a left : right a\\textit{left} : \\textit{right} aleft:right 是回文串,则取分割下标 i = right + 1 i = \textit{right} + 1 i=right+1 即符合要求;如果 b left : right b\\textit{left} : \\textit{right} bleft: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} aleft:right 和 b left : right b\\textit{left} : \\textit{right} bleft: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} aleft=bright 时,分别取分割下标为 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} aleft=bright,因此无论取哪个分割下标, 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}' aleft′:right′ 是回文串或 b left ′ : right ′ b\\textit{left}' : \\textit{right}' bleft′: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)。

相关推荐
j7~1 小时前
【算法】专题一:双指针之移动零,复写零,快乐数
数据结构·c++·算法·双指针·快乐数·移动零·复写零
江屿风8 天前
C++OJ题经验总结(竞赛)4
开发语言·c++·笔记·算法·dp·双指针
8Qi89 天前
LeetCode 209. 长度最小的子数组(Minimum Size Subarray Sum)
java·算法·leetcode·双指针·滑动窗口
happymaker062611 天前
LeetCodeHot100——盛水最多的容器
数据结构·算法·leetcode·双指针·hot100
像素猎人14 天前
洛谷题B3882:求回文数【双指针】
算法·双指针
量子炒饭大师20 天前
【优化算法】滑动窗口的「义体化」重构 ——【滑动窗口】何为滑动窗口?滑动窗口算法的核心目的是什么?
c++·算法·重构·优化算法·双指针·滑动窗口
Tisfy20 天前
LeetCode 2540.最小公共值:双指针(O(m+n))
算法·leetcode·题解·双指针
handler0124 天前
滑动窗口(同向双指针)算法:模板与例题解析
c语言·c++·笔记·算法·蓝桥杯·双指针·滑动窗口
量子炒饭大师1 个月前
【优化算法】双指针算法的「义体化」重构 ——【双指针】双指针算法中的指针是如何定义的?如何使用它进行一些简单的算法?
c++·算法·重构·优化算法·双指针
量子炒饭大师1 个月前
【优化算法:双指针算法刷题宝典】—— 三数之和
算法·优化算法·双指针·三数之和