📌  相关文章
📜  三元字符串中要替换的最少字符以删除 Q 查询的所有回文子字符串

📅  最后修改于: 2022-05-13 01:56:04.455000             🧑  作者: Mango

三元字符串中要替换的最少字符以删除 Q 查询的所有回文子字符串

给定一个长度为N的三元字符串S只包含'0''1''2'字符和Q查询包含一系列索引[L, R] ,每个查询[L, R]的任务是找到要转换为'0''1''2' 的最小字符数,这样在str[L]str[R]之间不存在长度至少为 2 的回文子串。

例子:

朴素方法:给定问题可以通过递归修改给定查询的子字符串的每个字符并检查结果子字符串是否具有回文子字符串来解决。

时间复杂度: O(Q*3 N )
辅助空间: O(N)

有效的方法:给定的问题可以使用动态规划来解决,想法是使用以下观察预处理所有子字符串的可能答案:

  • 如果 s i ≠ s i-1和 s i ≠ s i-2 ,则字符串有零个回文子串,即没有两个相邻字符相同,也没有两个替代字符相同,原因如下:
    • 如果相邻字符相同,则形成偶数长度回文。
    • 如果交替字符相同,则形成奇数长度回文。
  • 如果字符串的第一个字符是“0”,那么下一个字符必须是“1”或“2”(因为 s i ≠ s i-1
  • 如果第二个字符是 '1',那么第三个字符不能是 '0'(因为 s i ≠ s i-2 )或 '1'(因为 s i ≠ s i-1
  • 因此第三个字符将是“2”。那么第四个字符只能是'1'。形成的字符串是“012012012..”
  • 同样,在排列字符“0”、“1”和“2”并重复每个排列多次后,我们得到目标字符串“012012012…”、“120120120…”、“021021021…”等
  • “0”、“1”和“2”字符有六种可能的排列,因此有六个目标字符串

现在,每个查询都可以通过将子字符串从LR字符转换为六个目标字符串并检查其中哪些需要最少的操作来解决。这种方法每次查询都需要 O(N) 时间。该方法可以通过预处理给定的字符串进一步优化。以下是优化的解决方案:

  • prefix[i]为包含将字符串转换为目标字符串i所需的最少操作数的数组。因此, prefix[i][j]是将字符串的前j个字符转换为目标字符串i所需的操作数。
  • 在上述步骤的预处理之后,每个查询j可以在 O(1) 时间内使用每个可能的预处理字符串的公式作为currentCost(prefix[i][r j ] – prefix[i][l j – 1])用于所有可能的序列并打印成本。

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
#define SIZE 100005
using namespace std;
 
// Function to preprocess the cost of
// converting the first j character to
// each sequence prefix[i]
void preprocess(string& s, string& t,
                int prefix[][SIZE],
                int n, int i)
{
    // Initialize DP array
    prefix[i][0] = (s[0] != t[0]);
 
    for (int j = 1; j < n; j++) {
 
        // prefix[i][j] defines minimum
        // operations to transform first j
        // characters of s into sequence i
        prefix[i][j]
            = prefix[i][j - 1]
              + (s[j] != t[j % 3]);
    }
    return;
}
 
// Function to find the minimum number of
// changes required to make each substring
// between [L, R] non-palindromic
void minChangesNonPalindrome(
    string str, int N, int Q,
    vector > queries)
{
 
    // Initialize the DP array
    int prefix[6][SIZE];
 
    // Initialize the 6 different patterns
    // that can be formed to make substrings
    // non palindromic
    vector sequences
        = { "012", "021", "102",
            "120", "201", "210" };
 
    for (int i = 0; i < 6; i++) {
 
        // Preprocess the string with
        // the ith sequence
        preprocess(str, sequences[i],
                   prefix, N, i);
    }
 
    // Iterate through queries
    for (int i = 0; i < Q; i++) {
 
        int l = queries[i].first + 1,
            r = queries[i].second + 1;
        int cost = INT_MAX;
 
        // Find the minimum operations by
        // comparing 6 different patterns
        // of the substrings
        for (int j = 0; j < 6; j++) {
 
            // Find the cost
            cost
                = min(
                    cost,
                    prefix[j][r]
                        - prefix[j][l]
                        + (str[l] != sequences[j][l % 3]));
        }
        cout << cost << '\n';
    }
}
 
// Driver Code
int main()
{
    string S = "0200011011";
    vector > queries
        = { { 0, 4 }, { 1, 6 }, { 2, 8 } };
    int N = S.length();
    int Q = queries.size();
 
    minChangesNonPalindrome(
        S, N, Q, queries);
 
    return 0;
}


Python3
# Python 3 program for the above approach
import sys
SIZE = 100005
 
# Function to preprocess the cost of
# converting the first j character to
# each sequence prefix[i]
def preprocess(s,  t,
               prefix,
               n, i):
 
    # Initialize DP array
    prefix[i][0] = (s[0] != t[0])
 
    for j in range(1, n):
 
        # prefix[i][j] defines minimum
        # operations to transform first j
        # characters of s into sequence i
        prefix[i][j] = prefix[i][j - 1] + (s[j] != t[j % 3])
    return
 
# Function to find the minimum number of
# changes required to make each substring
# between [L, R] non-palindromic
def minChangesNonPalindrome(
        st, N, Q,
        queries):
 
    # Initialize the DP array
    prefix = [[0 for x in range(SIZE)]for y in range(6)]
 
    # Initialize the 6 different patterns
    # that can be formed to make substrings
    # non palindromic
    sequences = ["012", "021", "102",
                 "120", "201", "210"]
 
    for i in range(6):
 
        # Preprocess the string with
        # the ith sequence
        preprocess(st, sequences[i],
                   prefix, N, i)
 
    # Iterate through queries
    for i in range(Q):
 
        l = queries[i][0] + 1
        r = queries[i][1] + 1
        cost = sys.maxsize-1
 
        # Find the minimum operations by
        # comparing 6 different patterns
        # of the substrings
        for j in range(6):
 
            # Find the cost
            cost = min(cost, prefix[j][r] - prefix[j][l]
                       + (st[l] != sequences[j][l % 3]))
 
        print(cost)
 
# Driver Code
if __name__ == "__main__":
 
    S = "0200011011"
    queries = [[0, 4], [1, 6], [2, 8]]
    N = len(S)
    Q = len(queries)
 
    minChangesNonPalindrome(
        S, N, Q, queries)
 
    # This code is contributed by ukasp.


Javascript


输出:
2
3
3

时间复杂度: O(N + Q)
辅助空间: O(N)