通过递归删除所有相邻重复项来清空给定字符串的方法计数
给定一个字符串S ,一次就可以删除两个相邻的相等字符。删除后,已删除字符的两个端点都连接在一起。计算清空字符串的方法总数。
例子:
Input: S = aabccb
Output: 3
Explanation:
1. aabccb -> aabb -> aa
2. aabccb -> aabb -> bb
3. aabccb -> bccb -> bb
Hence, there are a total of 3 ways to empty the string after a valid set of moves.
Input: S = aabbc
Output: 0
Explanation: The string is of odd length, so it is not possible to empty the whole string.
方法:以上问题可以通过以下方式解决 动态规划。请按照以下步骤解决问题:
- 让我们定义一个二维 dp 表dp[i][j],它将存储范围 [i, j] 的答案。
- 定义递归方法来解决问题。
- 要计算dp[i][j] ,请遍历i和j之间的所有索引k ,其中S[i] = S[k] 。
- 现在对于个人k ,答案将是dp[i+1][k-1]*dp[k+1][j]*(安排删除范围的方法总数)。
- 要计算方程的最后一项,请注意整个范围[i+1, k-1]的删除将在S[i] 和 S[k] 删除之前发生。
- 因此,该范围内的总删除量将为(j – i + 1)/2 (因为一次删除了两个元素)。从这些移除中必须选择(j – k)/2 移除。
- 所以最终的公式将是
- 使用memoization不再重新计算状态。
- 检查递归函数中的基本情况。
- 最终答案将是dp[0][N-1]
下面是上述方法的实现:
C++
// C++ implementation for the above approach
#include
using namespace std;
// Define the dp table globally
int dp[505][505], choose[502][502];
// Recursive function to calculate the dp
// values for range [L, R]
int calc(int l, int r, string& s)
{
// The range is odd length
if (abs(r - l) % 2 == 0) {
return 0;
}
if (l > r) {
return dp[l][r] = 1;
}
// The state is already calculated
if (dp[l][r] != -1) {
return dp[l][r];
}
// If the length is 2
if ((r - l) == 1) {
if (s[l] == s[r]) {
dp[l][r] = 1;
}
else {
dp[l][r] = 0;
}
return dp[l][r];
}
// Total answer for this state
int ans = 0;
for (int k = l + 1; k <= r; k += 2) {
// Variable to store the current answer.
int temp = 1;
// Remove characters s[l] and s[i].
if (s[l] == s[k]) {
temp = calc(l + 1, k - 1, s)
* calc(k + 1, r, s)
* choose[(r - l + 1) / 2]
[(r - k) / 2];
ans += temp;
}
}
return dp[l][r] = ans;
}
int waysToClearString(string S)
{
// Initialize all the states of dp to -1
memset(dp, -1, sizeof(dp));
// Calculate all Combinations
int n = S.length();
choose[0][0] = 1;
for (int i = 1; i <= n / 2; ++i) {
choose[i][0] = 1;
for (int j = 1; j <= i; ++j) {
choose[i][j]
= (choose[i - 1][j]
+ choose[i - 1][j - 1]);
}
}
return calc(0, n - 1, S);
}
// Driver Code
int main()
{
string S = "aabccb";
cout << waysToClearString(S);
return 0;
}
Java
// Java program for the above approach
import java.io.*;
class GFG
{
// Define the dp table globally
static int [][]dp = new int[505][505];
static int [][]choose = new int[502][502];
// Recursive function to calculate the dp
// values for range [L, R]
static int calc(int l, int r, String s)
{
// The range is odd length
if (Math.abs(r - l) % 2 == 0) {
return 0;
}
if (l > r) {
return dp[l][r] = 1;
}
// The state is already calculated
if (dp[l][r] != -1) {
return dp[l][r];
}
// If the length is 2
if ((r - l) == 1) {
if (s.charAt(l) == s.charAt(r)) {
dp[l][r] = 1;
}
else {
dp[l][r] = 0;
}
return dp[l][r];
}
// Total answer for this state
int ans = 0;
for (int k = l + 1; k <= r; k += 2) {
// Variable to store the current answer.
int temp = 1;
// Remove characters s[l] and s[i].
if (s.charAt(l) == s.charAt(k)) {
temp = calc(l + 1, k - 1, s)
* calc(k + 1, r, s)
* choose[((r - l + 1) / 2)]
[((r - k) / 2)];
ans += temp;
}
}
return dp[l][r] = ans;
}
static int waysToClearString(String S)
{
// Initialize all the states of dp to -1
// Initialize all the states of dp to -1
for(int i=0;i<505;i++){
for(int j=0;j<505;j++)
dp[i][j] = -1;
}
// Calculate all Combinations
int n = S.length();
choose[0][0] = 1;
for (int i = 1; i <= (n / 2); ++i) {
choose[i][0] = 1;
for (int j = 1; j <= i; ++j) {
choose[i][j]
= (choose[i - 1][j]
+ choose[i - 1][j - 1]);
}
}
return calc(0, n - 1, S);
}
// Driver Code
public static void main (String[] args)
{
String S = "aabccb";
System.out.println(waysToClearString(S));
}
}
// This code is contributed by sanjoy_62.
Python3
# Python3 implementation for the above approach
import numpy as np
# Define the dp table globally
dp = np.zeros((505,505));
choose = np.zeros((502,502));
# Recursive function to calculate the dp
# values for range [L, R]
def calc(l, r, s) :
# The range is odd length
if (abs(r - l) % 2 == 0) :
return 0;
if (l > r) :
dp[l][r] = 1;
return dp[l][r]
# The state is already calculated
if (dp[l][r] != -1) :
return dp[l][r];
# If the length is 2
if ((r - l) == 1) :
if (s[l] == s[r]) :
dp[l][r] = 1;
else :
dp[l][r] = 0;
return dp[l][r];
# Total answer for this state
ans = 0;
for k in range(l + 1, r + 1, 2) :
# Variable to store the current answer.
temp = 1;
# Remove characters s[l] and s[i].
if (s[l] == s[k]) :
temp = calc(l + 1, k - 1, s) * calc(k + 1, r, s) * choose[(r - l + 1) // 2][(r - k) // 2];
ans += temp;
dp[l][r] = ans;
return dp[l][r]
def waysToClearString(S) :
# Initialize all the states of dp to -1
#memset(dp, -1, sizeof(dp));
for i in range(505):
for j in range(505) :
dp[i][j] = -1
# Calculate all Combinations
n = len(S);
choose[0][0] = 1;
for i in range(1, (n // 2) + 1) :
choose[i][0] = 1;
for j in range(1, i + 1) :
choose[i][j]= choose[i - 1][j] + choose[i - 1][j - 1];
return calc(0, n - 1, S);
# Driver Code
if __name__ == "__main__" :
S = "aabccb";
print(waysToClearString(S));
# This code is contributed by AnkThon
C#
// C# implementation for the above approach
using System;
using System.Collections.Generic;
class GFG{
// Define the dp table globally
static int [,]dp = new int[505,505];
static int [,]choose = new int[502,502];
// Recursive function to calculate the dp
// values for range [L, R]
static int calc(int l, int r, string s)
{
// The range is odd length
if (Math.Abs(r - l) % 2 == 0) {
return 0;
}
if (l > r) {
return dp[l,r] = 1;
}
// The state is already calculated
if (dp[l,r] != -1) {
return dp[l,r];
}
// If the length is 2
if ((r - l) == 1) {
if (s[l] == s[r]) {
dp[l,r] = 1;
}
else {
dp[l,r] = 0;
}
return dp[l,r];
}
// Total answer for this state
int ans = 0;
for (int k = l + 1; k <= r; k += 2) {
// Variable to store the current answer.
int temp = 1;
// Remove characters s[l] and s[i].
if (s[l] == s[k]) {
temp = calc(l + 1, k - 1, s)
* calc(k + 1, r, s)
* choose[(r - l + 1) / 2,(r - k) / 2];
ans += temp;
}
}
return dp[l,r] = ans;
}
static int waysToClearString(string S)
{
// Initialize all the states of dp to -1
for(int i=0;i<505;i++){
for(int j=0;j<505;j++)
dp[i,j] = -1;
}
// Calculate all Combinations
int n = S.Length;
choose[0,0] = 1;
for (int i = 1; i <= n / 2; ++i) {
choose[i,0] = 1;
for (int j = 1; j <= i; ++j) {
choose[i,j]
= (choose[i - 1,j]
+ choose[i - 1,j - 1]);
}
}
return calc(0, n - 1, S);
}
// Driver Code
public static void Main()
{
string S = "aabccb";
Console.Write(waysToClearString(S));
}
}
// This code is contributed by ipg2016107.
Javascript
输出
3
时间复杂度: O(N^3)
辅助空间: O(N^2)