LC-1616. 分割两个字符串得到回文串(相向双指针、中心扩展)

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

难度中等57

给你两个字符串 ab ,它们长度相同。请你选择一个下标,将两个字符串都在 相同的下标 分割开。由 a 可以得到两个字符串: aprefixasuffix ,满足 a = aprefix + asuffix ,同理,由 b 可以得到两个字符串 bprefixbsuffix ,满足 b = bprefix + bsuffix 。请你判断 aprefix + bsuffix 或者 bprefix + asuffix 能否构成回文串。

当你将一个字符串 s 分割成 sprefixssuffix 时, ssuffix 或者 sprefix 可以为空。比方说, s = "abc" 那么 "" + "abc""a" + "bc" "ab" + "c""abc" + "" 都是合法分割。

如果 能构成回文字符串 ,那么请返回 true,否则返回 false

注意x + y 表示连接字符串 xy

示例 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
  • ab 都只包含小写英文字母

暴力(超时)

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)

647. 回文子串

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/

  1. 题目给出的字符串长度固定,可以直接使用 中心扩展法 检测
    1. 由中心向两侧分别检测字符串 a 和 b
    2. 即【前 a 后 a】和【前 b 后 b】
    3. 不断扩展,直到字符不相同,中间部分都是回文串
    4. 结合下图观看,同时检测两条字符串,我们只关心回文更长的那串,具体是哪条更长不重要
  2. 当不符合回文串时,有一次机会将两个字符串拼接一下
    1. 继续扩展检测,这次检测拼接后的字符串
    2. 即【前 a 后 b】和【前 b 后 a】
    3. 结合下图观看,因为拼接的字符串既有 a 也有 b,所以之前更长的是哪串都不影响
  3. 当再次结束检测时
    1. 如字符再次不相同,则是匹配失败
    2. 如全部匹配,则 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;
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值