[1147. Multi-stage palindrome]

Source: LeetCode

describe:

you will get a string text. You should split it kinto substrings (subtext1, subtext2,…, subtextk), satisfying:

  • subtextiis a non- empty string
  • The concatenation of all substrings equals text(ie subtext1 + subtext2 + ... + subtextk == text)
  • This holds for iall valid values ​​of 1 <= i <= k, namelysubtexti == subtextk - i + 1

Returns the maximum kpossible value.

Example 1:

输入:text = "ghiabcdefhelloadamhelloabcdefghi"
输出:7
解释:我们可以把字符串拆分成 "(ghi)(abcdef)(hello)(adam)(hello)(abcdef)(ghi)"

Example 2:

输入:text = "merchant"
输出:1
解释:我们可以把字符串拆分成 "(merchant)"

Example 3:

输入:text = "antaprezatepzapreanta"
输出:11
解释:我们可以把字符串拆分成 "(a)(nt)(a)(pre)(za)(tpe)(za)(pre)(a)(nt)(a)"

hint:

  • 1 <= text.length <= 1000
  • text consists of lowercase English characters only

Method 1: greedy + double pointer

Ideas and Algorithms

The topic first gives a string text of length n, now we need to divide it into k non-empty substrings (subtext 1 , subtext 2 ,…, subtext k ), and need to satisfy subtext for 1 ≤ i ≤ k i = subtext k−i+1 is established, and all strings are connected in sequence to be equal to text. Now we need to calculate the maximum possible value of k. Now we use text[l, r] to represent text[l], text[l + 1], ..., text[r] this string interval, and the greedy scheme is given as follows:

Assuming that the non-empty string we need to split is text[l, r], 0 ≤ l ≤ r < n, then find the shortest length that can satisfy the same and non-overlapping prefix and suffix to split

  • If not found, text[l, r] as a whole returns 1 directly as a paragraph palindrome.
  • Otherwise, the string can be split into a prefix, the middle part and the suffix string
    • If the middle part of the string is not empty, return the maximum number of paragraph palindromes that the middle part of the string can be divided into plus 2.
    • Otherwise, the string text[l, r] can only be split into at most 2 segmental palindrome with prefix and suffix, just return 2 directly.

Then we follow this scheme to return the maximum number of paragraph palindrome that can be obtained from the string text[0, n − 1].

We now give a proof of this greedy scheme:

Suppose now given a string text[l, r], it has two identical and non-overlapping prefixes and suffixes of length len 1 and len 2 , where len 1 < len 2 . Now we need to prove that when splitting the string text[l, r], it is better to select the prefix and suffix with a length of len 1 than to select the prefix and suffix with a length of len 2 .

We record the string text[l, r] with a length of len 1 , the prefix and suffix is ​​A, the middle part of the string is X, the length of len 2 is AB, and the middle part of the string is Y. then we have

text[l, r] = (A)X(A) = (AB)Y(AB)
  • If the length of string B is greater than or equal to A, then B can be divided into the form of CA, where C can be an empty string. then there is
text[l, r] = (ACA)Y(ACA)

At this time, we can get on the basis of choosing the prefix as A

text[l, r] = (A)(C)(A)Y(A)(C)(A)

That is to say, at this time, we can get 4 more paragraph palindromes than directly dividing the suffix and suffix with a length of len 2 , so it is better to select the suffix and suffix of len 1 for segmentation at this time.

  • Otherwise, when the length of string B is less than A, string A can be divided into the form of CB. have
text[l, r] = (CBB)Y(CBB)

At this time, we can get on the basis of choosing the prefix as A

text[l, r] = (A)(B)Y(B)(A)

That is to say, at this time, we can get 2 more segmented palindromes than directly dividing the suffix and suffix with a length of len 2 , so it is better to select the suffix and suffix of len 1 for segmentation at this time.

To sum up, it is definitely better to select a suffix with a smaller length for segmentation than to select a suffix with a larger length for segmentation. That is, the correctness of the greedy scheme is proved.

code:

class Solution {
    
    
public:
    bool judge(const string& text, int l1, int l2, int len) {
    
    
        while (len --) {
    
    
            if (text[l1] != text[l2]) {
    
    
                return false;
            }
            ++l1;
            ++l2;
        }
        return true;
    }
    int longestDecomposition(string text) {
    
    
        int n = text.size();
        int res = 0;
        int l = 0, r = n - 1;
        while (l <= r) {
    
    
            int len = 1;
            while (l + len - 1 < r - len + 1) {
    
    
                if (judge(text, l, r - len + 1, len)) {
    
    
                    res += 2;
                    break;
                }
                ++len;
            }
            if (l + len - 1 >= r - len + 1) {
    
    
                ++res;
            }
            l += len;
            r -= len;
        }
        return res;
    }
};

Execution time: 0 ms, beats 100.00% of users in all C++ submissions
Memory consumption: 6.1 MB, beats 88.76% of users in all C++ submissions
Complexity analysis
Time complexity: O(n 2 ), where n is For the length of the string text, the time complexity of using "double pointer" to judge whether two strings are equal is O(n), which needs to be judged O(n) times, so the total time complexity is O(n 2 ) .
Space complexity: O(1), using only constant space.

Method Two: Rolling Hash

Ideas and Algorithms

In the implementation process of "Method 1", we can perform "rolling hash" preprocessing on the string text, so that when judging whether the prefix and suffix of a certain length of the string are the same, we can get the preceding hash in O(1) time. The hash value of the suffix is ​​used for judgment.

code:

class Solution {
    
    
public:
    vector<long long> pre1, pre2;
    vector<long long> pow1, pow2;
    static constexpr int MOD1 = 1000000007;
    static constexpr int MOD2 = 1000000009;
    int Base1, Base2;

    void init(string& s) {
    
    
        mt19937 gen{
    
    random_device{
    
    }()};
        Base1 = uniform_int_distribution<int>(1e6, 1e7)(gen);
        Base2 = uniform_int_distribution<int>(1e6, 1e7)(gen);
        while (Base2 == Base1) {
    
    
            Base2 = uniform_int_distribution<int>(1e6, 1e7)(gen);
        }
        int n = s.size();
        pow1.resize(n);
        pow2.resize(n);
        pre1.resize(n + 1);
        pre2.resize(n + 1);
        pow1[0] = pow2[0] = 1;
        pre1[1] = pre2[1] = s[0];
        for (int i = 1; i < n; ++i) {
    
    
            pow1[i] = (pow1[i - 1] * Base1) % MOD1;
            pow2[i] = (pow2[i - 1] * Base2) % MOD2;
            pre1[i + 1] = (pre1[i] * Base1 + s[i]) % MOD1;
            pre2[i + 1] = (pre2[i] * Base2 + s[i]) % MOD2;
        }
    }

    pair<int, int> getHash(int l, int r) {
    
    
        return {
    
    (pre1[r + 1] - ((pre1[l] * pow1[r + 1 - l]) % MOD1) + MOD1) % MOD1, (pre2[r + 1] - ((pre2[l] * pow2[r + 1 - l]) % MOD2) + MOD2) % MOD2};
    }

    int longestDecomposition(string text) {
    
    
        init(text);
        int n = text.size();
        int res = 0;
        int l = 0, r = n - 1;
        while (l <= r) {
    
    
            int len = 1;
            while (l + len - 1 < r - len + 1) {
    
    
                if (getHash(l, l + len - 1) == getHash(r - len + 1, r)) {
    
    
                    res += 2;
                    break;
                }
                ++len;
            }
            if (l + len - 1 >= r - len + 1) {
    
    
                ++res;
            }
            l += len;
            r -= len;
        }
        return res;
    }
};

Execution Time: 4 ms, beats 72.47% of all C++ submissions by users
Memory Consumption: 7 MB, beats 68.54% of all C++ submissions
Complexity Analysis
Time Complexity: O(n), where n is a character The length of the string text, the time complexity of preprocessing string hash is O(n), and the time complexity of double pointer is O(n).
Space complexity: O(n), where n is the length of the string text, which is mainly the space overhead of preprocessing the string hash.
author: LeetCode-Solution

Guess you like

Origin blog.csdn.net/Sugar_wolf/article/details/130099756