📌  相关文章
📜  通过从给定字符串删除最多K个字符,可以实现游程长度编码的最小长度

📅  最后修改于: 2021-06-25 11:17:45             🧑  作者: Mango

给定长度为N的字符串S (仅包含小写英文字母),任务是找到可以通过从字符串S除去最多K个字符来生成的游程长度编码的最小可能长度。

例子:

天真的方法:解决该问题的最简单方法是从字符串删除K个字符的每个组合,并计算它们各自的游程长度编码。最后,打印获得的最小游程长度编码的长度。

时间复杂度: O(K * N!(N – K)!* K!)
辅助空间: O(K)

高效方法:要优化上述方法,请按照以下步骤解决问题:

  • 维护一个辅助数组dp [n] [k] [26] [n] ,其中dp [idx] [K] [last] [count]表示从索引idx开始获得的最小游程长度编码,其中K表示剩余的删除次数, last表示到目前为止具有频率计数的最后一个字符。
  • 对于每个字符,存在两种可能性,即删除字符或保留字符。
  • 考虑删除索引idx处的当前字符,并递归计算通过传递参数(idx + 1,K – 1,last,count)获得的最小游程长度编码
  • 现在,请考虑保留索引idx处的当前字符,并递归计算以下两种情况的最小游程长度编码:
  • 如果S [idx] = last:通过传递参数(idx + 1,K,S [idx],count + 1)计算最小游程编码。
  • 否则,通过传递参数(idx + 1,K,S [idx],1)来计算最小游程编码。
  • 返回上述计算值的最小值,并对字符串的所有索引重复上述步骤。

下面是上述方法的实现:

C++
// C++ Program to implement
// the above approach
 
#include 
using namespace std;
 
#define maxN 20
 
int dp[maxN][maxN][27][maxN];
 
// Function which solves the desired problem
int solve(string& s, int n, int idx,
          int k, char last = 123,
          int count = 0)
{
    // idx: current index in s
    // k: Remaining number of deletions
    // last: Previous character
    // count: Number of occurrences
    // of the previous character
 
    // Base Case
    if (k < 0)
        return n + 1;
 
    // If the entire string has
    // been traversed
    if (idx == n)
        return 0;
 
    int& ans = dp[idx][k][last - 'a'][count];
 
    // If precomputed subproblem
    // occurred
    if (ans != -1)
        return ans;
 
    ans = n + 1;
 
    // Minimum run length encoding by
    // removing the currrent character
    ans = min(ans,
              solve(s, n, idx + 1, k - 1, last, count));
 
    // Minimum run length encoding by
    // retaining the currrent character
    int inc = 0;
 
    if (count == 1 || count == 9
        || count == 99)
        inc = 1;
 
    // If the current and the
    // previous characters match
    if (last == s[idx]) {
 
        ans = min(ans,
                  inc + solve(s, n, idx + 1, k, s[idx],
                              count + 1));
    }
 
    // Otherwise
    else {
 
        ans = min(ans,
                  1 + solve(s, n, idx + 1, k, s[idx], 1));
    }
 
    return ans;
}
 
// Function to return minimum run-length encoding
// for string s by removing atmost k characters
int MinRunLengthEncoding(string& s, int n, int k)
{
    memset(dp, -1, sizeof(dp));
    return solve(s, n, 0, k);
}
 
// Driver Code
int main()
{
    string S = "abbbcdcdd";
    int N = 9, K = 2;
    cout << MinRunLengthEncoding(S, N, K);
 
    return 0;
}


Java
// Java program to implement
// the above approach
import java.util.*;
 
class GFG{
 
static int maxN = 20;
 
static int dp[][][][] = new int[maxN][maxN][27][maxN];
 
// Function which solves the desired problem
public static int solve(String s, int n,
                         int idx, int k,
                       char last, int count)
{
     
    // idx: current index in s
    // k: Remaining number of deletions
    // last: Previous character
    // count: Number of occurrences
    // of the previous character
 
    // Base Case
    if (k < 0)
        return n + 1;
 
    // If the entire string has
    // been traversed
    if (idx == n)
        return 0;
 
    int ans = dp[idx][k][last - 'a'][count];
 
    // If precomputed subproblem
    // occurred
    if (ans != -1)
        return ans;
 
    ans = n + 1;
 
    // Minimum run length encoding by
    // removing the currrent character
    ans = Math.min(ans, solve(s, n, idx + 1,
                              k - 1, last,
                              count));
 
    // Minimum run length encoding by
    // retaining the currrent character
    int inc = 0;
 
    if (count == 1 || count == 9 || count == 99)
        inc = 1;
 
    // If the current and the
    // previous characters match
    if (last == s.charAt(idx))
    {
        ans = Math.min(ans, inc + solve(s, n, idx + 1,
                                        k, s.charAt(idx),
                                        count + 1));
    }
 
    // Otherwise
    else
    {
        ans = Math.min(ans, 1 + solve(s, n, idx + 1, k,
                                      s.charAt(idx), 1));
    }
    return dp[idx][k][last - 'a'][count] = ans;
}
 
// Function to return minimum run-length encoding
// for string s by removing atmost k characters
public static int MinRunLengthEncoding(String s, int n,
                                                 int k)
{
    for(int i[][][] : dp)
        for(int j[][] : i)
            for(int p[] : j)
                Arrays.fill(p, -1);
                 
    return solve(s, n, 0, k, (char)123, 0);
}
 
// Driver Code
public static void main(String args[])
{
    String S = "abbbcdcdd";
    int N = 9, K = 2;
     
    System.out.println(MinRunLengthEncoding(S, N, K));
}
}
 
// This code is contributed by hemanth gadarla


Python3
# Python3 program to implement
# the above approach
maxN = 20
 
dp = [[[[0 for i in range(maxN)]
           for j in range(27)]
           for k in range(27)]
           for l in range(maxN)]
 
# Function which solves the desired problem
def solve(s, n, idx, k, last, count):
     
    # idx: current index in s
    # k: Remaining number of deletions
    # last: Previous character
    # count: Number of occurrences
    # of the previous character
 
    # Base Case
    if (k < 0):
        return n + 1
 
    # If the entire string has
    # been traversed
    if (idx == n):
        return 0
 
    ans = dp[idx][k][ord(last) - ord('a')][count]
 
    # If precomputed subproblem
    # occurred
    if (ans != -1):
        return ans
 
    ans = n + 1
 
    # Minimum run length encoding by
    # removing the currrent character
    ans = min(ans, solve(s, n, idx + 1,
                         k - 1, last, count))
 
    # Minimum run length encoding by
    # retaining the currrent character
    inc = 0
 
    if (count == 1 or count == 9 or
        count == 99):
        inc = 1
 
    # If the current and the
    # previous characters match
    if (last == s[idx]):
        ans = min(ans, inc + solve(s, n, idx + 1, k,
                                   s[idx], count + 1))
 
    # Otherwise
    else:
        ans = max(ans, 1 + solve(s, n, idx + 1,
                                 k, s[idx], 1))
                                  
    dp[idx][k][ord(last) - ord('a')][count] = ans
    #print(ans)
     
    return dp[idx][k][ord(last) - ord('a')][count]
 
# Function to return minimum run-length encoding
# for string s by removing atmost k characters
def MinRunLengthEncoding(s, n, k):
     
    for i in range(maxN):
        for j in range(27):
            for k in range(27):
                for l in range(maxN):
                    dp[i][j][k][l] = -1
                     
    return solve(s, n, 0, k, chr(123), 0) - 1
 
# Driver Code
if __name__ == '__main__':
     
    S = "abbbcdcdd"
    N = 9
    K = 2
 
    print(MinRunLengthEncoding(S, N, K))
 
# This code is contributed by gauravrajput1


C#
// C# program to implement
// the above approach
using System;
class GFG{
 
static int maxN = 20;
 
static int [,,,]dp =
       new int[maxN, maxN,
               27, maxN];
 
// Function which solves
// the desired problem
public static int solve(String s, int n,
                        int idx, int k,
                        char last, int count)
{   
  // idx: current index in s
  // k: Remaining number of deletions
  // last: Previous character
  // count: Number of occurrences
  // of the previous character
 
  // Base Case
  if (k < 0)
    return n + 1;
 
  // If the entire string
  // has been traversed
  if (idx == n)
    return 0;
 
  int ans = dp[idx, k, last -
               'a', count];
 
  // If precomputed subproblem
  // occurred
  if (ans != -1)
    return ans;
 
  ans = n + 1;
 
  // Minimum run length encoding by
  // removing the currrent character
  ans = Math.Min(ans,
                 solve(s, n, idx + 1,
                       k - 1, last,
                       count));
 
  // Minimum run length encoding by
  // retaining the currrent character
  int inc = 0;
 
  if (count == 1 || count == 9 ||
      count == 99)
    inc = 1;
 
  // If the current and the
  // previous characters match
  if (last == s[idx])
  {
    ans = Math.Min(ans, inc +
                   solve(s, n, idx + 1,
                         k, s[idx],
                         count + 1));
  }
 
  // Otherwise
  else
  {
    ans = Math.Min(ans, 1 +
                   solve(s, n, idx + 1,
                         k, s[idx], 1));
  }
  return dp[idx, k, last -
            'a', count] = ans;
}
 
// Function to return minimum
// run-length encoding for string
// s by removing atmost k characters
public static int MinRunLengthEncoding(String s,
                                       int n, int k)
{
  for (int i = 0; i < maxN; i++)
    for (int j = 0; j < maxN; j++)
      for (int p = 0; p < 27; p++)
        for (int l = 0; l < maxN; l++)
          dp[i, j, p, l] = -1;
 
  return solve(s, n, 0,
               k, (char)123, 0);
}
 
// Driver Code
public static void Main(String []args)
{
  String S = "abbbcdcdd";
  int N = 9, K = 2;
  Console.WriteLine(
          MinRunLengthEncoding(S,
                               N, K));
}
}
 
// This code is contributed by 29AjayKumar


输出:
5













时间复杂度: O(26 * N 2 * K)
辅助空间: O(26 * N 2 * K)