给定长度为N的字符串S (仅包含小写英文字母),任务是找到可以通过从字符串S除去最多K个字符来生成的游程长度编码的最小可能长度。
例子:
Input: S = “abbbcdcdd”, N = 9, K = 2
Output: 5
Explanation: One possible way is to delete both occurrences of ‘c’ from S.
The new string generated is “abbbddd” whose run-length-encoding is “ab3d3”.
Therefore, the length of the encoded string is 5.
Input: S = “aabbca”, N = 6, K = 3
Output: 2
Explanation: One possible way is to delete both the occurrences of ‘b’ and one occurrence of ‘c’.
The new string generated is “aaa” whose run-length-encoding is “a3”.
Therefore, the length of the encoded string is 2
天真的方法:解决该问题的最简单方法是从字符串删除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)