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

发布时间 2023-04-08 23:33:35作者: lxy_cn

题目链接:1616. 分割两个字符串得到回文串

方法:模拟 + 双指针

解题思路

  1. 题目要求,找一个合适的下标 \(idx\)\(a\) 分割为 \(a[0, idx]\)\(a[idx + 1, n - 1]\),同样的 \(b\) 分割为 \(b[0, idx]\)\(b[idx + 1, n - 1]\),然后使得 \(a[0, idx] + b[idx + 1, n - 1]\)\(b[0, idx] + a[idx + 1, n - 1]\) 为回文字符串,若存在下标 \(idx\),则返回 true,否则返回 false
  2. 若是 \(a[0, idx] + b[idx + 1, n - 1]\) 为回文串,则从左→右遍历 \(a\),从右←左遍历 \(b\),判断是否可能存在回文串;同理若是 \(b[0, idx] + a[idx + 1, n - 1]\)为回文字符串,则改变遍历方向,从左→右遍历 \(b\),从右←左遍历 \(a\),判断是否可能存在回文串;
  3. 实际上上述的两个过程是相同的,那么可以写成一个函数形式 \(check()\),在传参数时分别为 \(check(a, b)\)\(check(b, a)\) 即对应上述两种过程。
  4. 如何检查上述情况是否存在?
    对于 \(check(a, b)\):初始化 \(l = 0, r = n - 1\),从左→右遍历 \(a\),从右←左遍历 \(b\),当 \(a[l] != b[r]\) 时,检查 \(a[l, r]\)\(b[l, r]\) 是否为回文串,若有一个则返回 true,假设是 \(a[l, r]\) 为回文串,则 \(a[0, l - 1] + a[l, r] + b[r + 1, n - 1]\) 构成回文串,此时 \(idx = r\)

代码

// 优化后代码
class Solution {
public:
    bool checkPalindrome(string str) {
        int n = str.length();
        for (int i = 0; i < n / 2; i ++ ) {
            if (str[i] != str[n - i - 1]) {
                return false;
            } 
        }
        return true;
    }
    bool check(string a, string b) {
        int n = a.length();
        int l = 0, r = n - 1;
        while (l < r) {
            if (a[l] == b[r]) {
                l ++ ;
                r --;
            } else {
                break;
            }
        }
        if (checkPalindrome(a.substr(l, r - l + 1)) || checkPalindrome(b.substr(l, r - l + 1))) return true;
        return false;
    }
    bool checkPalindromeFormation(string a, string b) {
        // 从左→右遍历a,从右←左遍历b,判断是否可能存在回文串
        // 改变遍历方向,从左→右遍历b,从右←左遍历a,判断是否可能存在回文串
        return check(a, b) || check(b, a);
    }
};
// 优化前代码
class Solution {
public:
    bool checkPalindromeFormation(string a, string b) {
        int n = a.length();
        // a 和 b有一个为回文串,则返回true
        int flag1 = true, flag2 = true;
        for (int i = 0; i <= n / 2; i ++ ) {
            if (a[i] != a[n - i - 1]) {
                flag1 = false;
            } 
            if (b[i] != b[n - i - 1]) {
                flag2 = false;
            } 
        }
        if (flag1 || flag2) return true;
        // 从左→右遍历a,从右←左遍历b,判断是否可能存在回文串
        int l = 0, r = n - 1;
        while (l < r) {
            if (a[l] == b[r]) {
                l ++ ;
                r --;
            } else {
                break;
            }
        }
        if (r == l - 1 || r == l) return true; // 说明左右指针相遇,即可以在此截断,此时a[0, l - 1] + b[l, n - 1]为回文串,此时分开下标为l - 1。
        else if (r - l + 1 != n) { // 否则表明左右指针未相遇,在继续判断a[l, r] 或 b[l, r]是否为回文串,假设a[l, r]为回文串,则a[0, r] + b[r + 1, n - 1]为回文串,此时分开下标为r。
            int left = l, right = r;
            while (left < right) {
                if (a[left] == a[right]) {
                    left ++ ;
                    right -- ;
                } else {
                    break;
                }
            }
            if (left - 1 == right || left == right) return true;
            left = l, right = r;
            while (left < right) {
                if (b[left] == b[right]) {
                    left ++ ;
                    right -- ;
                } else {
                    break;
                }
            }
            if (left - 1 == right || left == right) return true;
        }
        // 同上,改变遍历方向,从左→右遍历b,从右←左遍历a,判断是否可能存在回文串
        l = 0, r = n - 1;
        while (l < r) {
            if (b[l] == a[r]) {
                l ++ ;
                r --;
            } else {
                break;
            }
        }
        if (r == l - 1 || r == l) return true;
        else if (r - l + 1 != n) {
            int left = l, right = r;
            while (left < right) {
                if (a[left] == a[right]) {
                    left ++ ;
                    right -- ;
                } else {
                    break;
                }
            }
            if (left - 1 == right || left == right) return true;
            left = l, right = r;
            while (left < right) {
                if (b[left] == b[right]) {
                    left ++ ;
                    right -- ;
                } else {
                    break;
                }
            }
            if (left - 1 == right || left == right) return true;

        }
        return false;
    }
};

复杂度分析

时间复杂度:\(O(n)\)
空间复杂度:\(O(1)\)