📜  计算构造目标字符串的方法数

📅  最后修改于: 2021-09-17 06:56:47             🧑  作者: Mango

给定字符串数组A中,每个具有相同的长度和目标字符串的S,找到方法来构建给定阵列中使用的字符从字符串目标字符串的数目,使得在字符串结构形式的严格使用的字符的索引递增序列。也可以在同一个字符串使用多个字符。由于答案可能非常大,取模与 (10^9 + 7)

例子:

Input :  A = ["adc", "aec", "erg"], S = "ac"
Output : 4
Target string can be formed in following ways :
1) 1st character of "adc" and the 3rd character of "adc".
2) 1st character of "adc" and the 3rd character of "aec".
3) 1st character of "aec" and the 3rd character of "adc".
4) 1st character of "aec" and the 3rd character of "aec".

Input : A = ["afsdc", "aeeeedc", "ddegerg"], S = "ae"
Output : 12 

方法

  • 我们将使用动态规划来解决这个问题。
  • 对于数组中的每个字符串,存储在其中发生的字符字符串中在共同的列表(L)的位置。我们的目标是使用索引形成严格递增序列的字符,因此它们来自哪个字符串并不重要。
  • 遍历目标字符串,保留之前选取的索引(prev)的信息。对于目标的当前位置,通过在 L 中搜索,字符串检查该字符是否出现在任何大于 prev 的索引处。这可以使用递归来完成,但我们可以使用 dp 表记住它。
Following are the states of dp :
dp[pos][prev], 
where pos represents the position we are at in the target string, 
and prev represents the previously picked index.

下面是上述方法的实现:

C++
// C++ Program to Count the number of ways to
// construct the target string
#include 
 
using namespace std;
 
int mod = 1000000007;
 
int dp[1000][1000];
 
int calculate(int pos, int prev, string s, vector* index)
{
 
    // base case
    if (pos == s.length())
        return 1;
 
    // If current subproblem has been solved, use the value
    if (dp[pos][prev] != -1)
        return dp[pos][prev];
 
    // current character
    int c = s[pos] - 'a';
 
    // search through all the indiced at which the current
    // character occurs. For each index greater than prev,
    // take the index and move
    // to the next position, and add to the answer.
    int answer = 0;
    for (int i = 0; i < index.size(); i++) {
        if (index[i] > prev) {
            answer = (answer % mod + calculate(pos + 1,
                         index[i], s, index) % mod) % mod;
        }
    }
 
    // Store and return the solution for this subproblem
    return dp[pos][prev] = answer;
}
 
int countWays(vector& a, string s)
{
    int n = a.size();
 
    // preprocess the strings by storing for each
    // character of every string, the index of their
    // occurrence we will use a common list for all
    // because of only the index matter
    // in the string from which the character was picked
    vector index[26];
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < a[i].length(); j++) {
 
            // we are storing j+1 because the initial picked index
            // in the recursive step will ne 0.
            // This is just for ease of implementation
            index[a[i][j] - 'a'].push_back(j + 1);
        }
    }
 
    // initialise dp table. -1 represents that
    // the subproblem hasn't been solved
    memset(dp, -1, sizeof(dp));
 
    return calculate(0, 0, s, index);
}
 
// Driver Code
int main()
{
    vector A;
    A.push_back("adc");
    A.push_back("aec");
    A.push_back("erg");
 
    string S = "ac";
 
    cout << countWays(A, S);
 
    return 0;
}


Java
// Java Program to Count the number of ways to
// construct the target String
import java.util.*;
 
class GFG{
  
static int mod = 1000000007;
  
static int [][]dp = new int[1000][1000];
  
static int calculate(int pos, int prev, String s, Vector index)
{
  
    // base case
    if (pos == s.length())
        return 1;
  
    // If current subproblem has been solved, use the value
    if (dp[pos][prev] != -1)
        return dp[pos][prev];
 
  
    // search through all the indiced at which the current
    // character occurs. For each index greater than prev,
    // take the index and move
    // to the next position, and add to the answer.
    int answer = 0;
    for (int i = 0; i < index.size(); i++) {
        if (index.get(i).compareTo(prev) >= 0) {
            answer = (answer % mod + calculate(pos + 1,
                         index.get(i), s, index) % mod) % mod;
        }
    }
  
    // Store and return the solution for this subproblem
    return dp[pos][prev] = answer;
}
  
static int countWays(Vector a, String s)
{
    int n = a.size();
  
    // preprocess the Strings by storing for each
    // character of every String, the index of their
    // occurrence we will use a common list for all
    // because of only the index matter
    // in the String from which the character was picked
    Vector []index = new Vector[26];
    for (int i = 0; i < 26; i++)
        index[i] = new Vector();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < a.get(i).length(); j++) {
  
            // we are storing j+1 because the initial picked index
            // in the recursive step will ne 0.
            // This is just for ease of implementation
            index[a.get(i).charAt(j) - 'a'].add(j + 1);
        }
    }
  
    // initialise dp table. -1 represents that
    // the subproblem hasn't been solved
    for(int i = 0;i< 1000;i++)
    {
        for (int j = 0; j < 1000; j++) {
            dp[i][j] = -1;
        }
    }
  
    return calculate(0, 0, s, index[0]);
}
  
// Driver Code
public static void main(String[] args)
{
    Vector A = new Vector();
    A.add("adc");
    A.add("aec");
    A.add("erg");
  
    String S = "ac";
  
    System.out.print(countWays(A, S));
}
}
 
// This code is contributed by Princi Singh


Python3
# Python 3 Program to Count the number of ways to
# construct the target string
 
mod = 1000000007
 
dp = [[-1 for i in range(1000)] for j in range(1000)];
 
def calculate(pos, prev, s,index):
    # base case
    if (pos == len(s)):
        return 1
 
    # If current subproblem has been solved, use the value
    if (dp[pos][prev] != -1):
        return dp[pos][prev]
 
    # current character
    c = ord(s[pos]) - ord('a');
 
    # search through all the indiced at which the current
    # character occurs. For each index greater than prev,
    # take the index and move
    # to the next position, and add to the answer.
    answer = 0
    for i in range(len(index)):
        if (index[i] > prev):
            answer = (answer % mod + calculate(pos + 1,index[i], s, index) % mod) % mod
             
    dp[pos][prev] = 4
 
    # Store and return the solution for this subproblem
    return dp[pos][prev]
 
def countWays(a, s):
    n = len(a)
 
    # preprocess the strings by storing for each
    # character of every string, the index of their
    # occurrence we will use a common list for all
    # because of only the index matter
    # in the string from which the character was picked
    index = [[] for i in range(26)]
 
    for i in range(n):
        for j in range(len(a[i])):
            # we are storing j+1 because the initial picked index
            # in the recursive step will ne 0.
            # This is just for ease of implementation
            index[ord(a[i][j]) - ord('a')].append(j + 1);
 
    # initialise dp table. -1 represents that
    # the subproblem hasn't been solve
 
    return calculate(0, 0, s, index[0])
 
# Driver Code
if __name__ == '__main__':
    A = []
    A.append("adc")
    A.append("aec")
    A.append("erg")
 
    S = "ac"
 
    print(countWays(A, S))
 
# This code is contributed by Surendra_Gangwar


C#
// C# Program to Count the number of ways to
// construct the target String
using System;
using System.Collections.Generic;
 
class GFG{
   
static int mod = 1000000007;
   
static int [,]dp = new int[1000,1000];
   
static int calculate(int pos, int prev, String s, List index)
{
   
    // base case
    if (pos == s.Length)
        return 1;
   
    // If current subproblem has been solved, use the value
    if (dp[pos,prev] != -1)
        return dp[pos,prev];
  
   
    // search through all the indiced at which the current
    // character occurs. For each index greater than prev,
    // take the index and move
    // to the next position, and add to the answer.
    int answer = 0;
    for (int i = 0; i < index.Count; i++) {
        if (index[i].CompareTo(prev) >= 0) {
            answer = (answer % mod + calculate(pos + 1,
                         index[i], s, index) % mod) % mod;
        }
    }
   
    // Store and return the solution for this subproblem
    return dp[pos,prev] = answer;
}
   
static int countWays(List a, String s)
{
    int n = a.Count;
   
    // preprocess the Strings by storing for each
    // character of every String, the index of their
    // occurrence we will use a common list for all
    // because of only the index matter
    // in the String from which the character was picked
    List []index = new List[26];
    for (int i = 0; i < 26; i++)
        index[i] = new List();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < a[i].Length; j++) {
   
            // we are storing j+1 because the initial picked index
            // in the recursive step will ne 0.
            // This is just for ease of implementation
            index[a[i][j] - 'a'].Add(j + 1);
        }
    }
   
    // initialise dp table. -1 represents that
    // the subproblem hasn't been solved
    for(int i = 0;i< 1000;i++)
    {
        for (int j = 0; j < 1000; j++) {
            dp[i,j] = -1;
        }
    }
   
    return calculate(0, 0, s, index[0]);
}
   
// Driver Code
public static void Main(String[] args)
{
    List A = new List();
    A.Add("adc");
    A.Add("aec");
    A.Add("erg");
   
    String S = "ac";
   
    Console.Write(countWays(A, S));
}
}
 
// This code is contributed by sapnasingh4991


Python3
from collections import defaultdict,Counter
 
# total ways calculator function
def numWays(words,target):
   
    # length of first word
    m = len(words[0])
     
    # length of the target
    n = len(target)
     
    # storing in default dict
    positions = defaultdict(Counter)
     
     # traversing array
    for i in range(len(words)):
       
        # traversing like 2d row and col
        for j in range(m):
           
            # store the occurrences in dict
            positions[j][words[i][j]] += 1
                 
    # define the back function   
    def back(i, start):
       
        # if i is equal to n
        if i==n:
            return 1
         
        # if start is equal to m
        if start==m:
            return 0
           
        # initialize the ans with 0 
        ans = 0
         
        # recursive call and store
        # the result in ans variable
        ans += back(i, start + 1)
         
        # check the condition
        if positions[start][target[i]]:
           
            # multiply with the each character and the recursive call
            ans += positions[start][target[i]] * back(i + 1, start + 1)
        return ans
  
    return back(0,0)
 
# Function Call
words = ["abba","baab"]
target = "bab"
print(numWays(words,target))
 
# This code is contributed by saikumar kudikala


输出:
4

时间复杂度: O(M * N 2 ),其中 M 是目标字符串的长度,N 是每个数组字符串的长度。

方法:(动态编程+计数器+双指针)

  1. 这个想法是首先通过遍历默认字典中的所有可能位置来存储字符串的所有出现
  2. 现在定义另一个函数并通过将两个指针放在第 0 个索引上并从第 0 个位置开始并开始递归
  3. 首先对于递归,我们应该定义基本情况以便在某个时刻终止递归

下面提到了基本情况:

主要条件:

  • 现在我们将执行对递归并检查是否可以从给定的字符串形成目标,如果是,我们将简单地增加计数器:
  • 同样,我们将递归调用与给定的字符串相乘,并检查是否可以从字符串生成目标:
  • 最后,我们返回答案
Time complexity:  O(2^n)
space complexity: O(N)

执行:

蟒蛇3

from collections import defaultdict,Counter
 
# total ways calculator function
def numWays(words,target):
   
    # length of first word
    m = len(words[0])
     
    # length of the target
    n = len(target)
     
    # storing in default dict
    positions = defaultdict(Counter)
     
     # traversing array
    for i in range(len(words)):
       
        # traversing like 2d row and col
        for j in range(m):
           
            # store the occurrences in dict
            positions[j][words[i][j]] += 1
                 
    # define the back function   
    def back(i, start):
       
        # if i is equal to n
        if i==n:
            return 1
         
        # if start is equal to m
        if start==m:
            return 0
           
        # initialize the ans with 0 
        ans = 0
         
        # recursive call and store
        # the result in ans variable
        ans += back(i, start + 1)
         
        # check the condition
        if positions[start][target[i]]:
           
            # multiply with the each character and the recursive call
            ans += positions[start][target[i]] * back(i + 1, start + 1)
        return ans
  
    return back(0,0)
 
# Function Call
words = ["abba","baab"]
target = "bab"
print(numWays(words,target))
 
# This code is contributed by saikumar kudikala
输出
4