📌  相关文章
📜  使用给定的字符集最大程度地形成一组单词的成本

📅  最后修改于: 2021-05-24 19:27:38             🧑  作者: Mango

给定一个由N个字符串组成的数组arr [] ,由M个小写字符组成的数组letter []和一个数组score [] ,使得score [i]是第i英语字母的代价,任务是找到最大值使用给定字母形成的任何有效单词集的成本,这样每个字母最多可以使用一次,每个单词arr [i]最多可以形成一次。

例子:

方法:可以通过使用递归来解决给定的问题。想法是生成给定数组arr []的所有可能子集,如果存在任何子集,其所有字符串都可以由给定字母组成,则通过添加所用字母的成本来找到该子集的成本。请按照以下步骤解决问题:

  • 维持频率阵列,频率[]的字符的频率存储在数组中,字母
  • 调用递归函数helper() ,该函数以start (最初为0), words []freq []score []数组作为参数。
    • start = N时处理基本条件,然后返回0。
    • 否则,将数组freq []的内容复制到另一个数组freqCopy []中
    • currScorewordScore初始化为0,以存储最大分数和从当前单词获得的分数。
    • 更新wordScore如果所有的当前字的它的字符,即字[开始]存在于阵列,freqCopy在,然后更新freqCopy。
    • 通过将wordScore添加到递归调用函数helper()返回的值中,并通过将start + 1words []freqCopy []score []数组作为参数传递来包含当前单词。
    • 通过递归调用函数helper()并传递start + 1words []freq []score []数组作为参数来排除当前单词。
    • 将最高分数存储在currScore的两个分数中,并返回其值。
  • 完成上述步骤后,打印由该函数返回的值。

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
// Utility function to find
// maximum cost of generating
// any possible subsets of strings
int helper(vector words, int start,
    vector letterCounts, vector score)
{
   
    // Base Case
    if (start == words.size())
        return 0;
 
    // Stores the current cost
    int currScore = 0;
 
    // Stores the cost of
    // by the current word
    int wordScore = 0;
 
    // Create a copy of the
    // letterCounts array
    vector nextCounts = letterCounts;
 
    // Traverse the current word
    for (int i = 0;
         i < words[start].size();
         ++i) {
 
        // Store the current index & check
        // if its frequency is 0 or not
        int idx = words[start][i] - 'a';
 
        if (nextCounts[idx] == 0) {
 
            // If true, then update
            // wordScore to -1
            wordScore = -1;
            break;
        }
 
        // Otherwise, add the cost of
        // the current index to wordScore
        wordScore += score[idx];
 
        // Decrease its frequency
        nextCounts[idx]--;
    }
 
    // If wordScore > 0, then
    // recursively call for next index
    if (wordScore > 0)
        currScore = helper(words,
                           start + 1,
                           nextCounts,
                           score)
                    + wordScore;
 
    // Find the cost by not
    // including current word
    currScore = max(
        currScore, helper(words, start + 1,
                          letterCounts,
                          score));
 
    // Return the maximum score
    return currScore;
}
 
// Function to find the maximum cost
// of any valid set of words formed
// by using the given letters
int maxScoreWords(vector words, vector letters,
    vector score)
{
    // Stores frequency of characters
    vector letterCounts(26,0);
 
    for (char letter : letters)
        letterCounts[letter - 'a']++;
 
    // Find the maximum cost
    return helper(words, 0,
                  letterCounts,
                  score);
}
 
// Driver Code
int main()
{
    // Given arrays
    vector words = { "dog", "cat", "dad", "good" };
    vector letters = { 'a', 'a', 'c', 'd', 'd','d', 'g', 'o', 'o' };
    vector score= { 1, 0, 9, 5, 0, 0, 3, 0, 0, 0, 0, 0, 0,
            0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
    // Function Call
    cout<<(maxScoreWords(words, letters, score));
}
 
// This  code is contributed by mohit kumar 29.


Java
// Java program for the above approach
import java.io.*;
class GFG {
 
    // Function to find the maximum cost
    // of any valid set of words formed
    // by using the given letters
    public static int maxScoreWords(
        String[] words, char[] letters,
        int[] score)
    {
        // Stores frequency of characters
        int[] letterCounts = new int[26];
 
        for (char letter : letters)
            letterCounts[letter - 'a']++;
 
        // Find the maximum cost
        return helper(words, 0,
                      letterCounts,
                      score);
    }
 
    // Utility function to find
    // maximum cost of generating
    // any possible subsets of strings
    public static int helper(
        String[] words, int start,
        int[] letterCounts, int[] score)
    {
        // Base Case
        if (start == words.length)
            return 0;
 
        // Stores the current cost
        int currScore = 0;
 
        // Stores the cost of
        // by the current word
        int wordScore = 0;
 
        // Create a copy of the
        // letterCounts array
        int[] nextCounts
            = letterCounts.clone();
 
        // Traverse the current word
        for (int i = 0;
             i < words[start].length();
             ++i) {
 
            // Store the current index & check
            // if its frequency is 0 or not
            int idx = words[start].charAt(i) - 'a';
 
            if (nextCounts[idx] == 0) {
 
                // If true, then update
                // wordScore to -1
                wordScore = -1;
                break;
            }
 
            // Otherwise, add the cost of
            // the current index to wordScore
            wordScore += score[idx];
 
            // Decrease its frequency
            nextCounts[idx]--;
        }
 
        // If wordScore > 0, then
        // recursively call for next index
        if (wordScore > 0)
            currScore = helper(words,
                               start + 1,
                               nextCounts,
                               score)
                        + wordScore;
 
        // Find the cost by not
        // including current word
        currScore = Math.max(
            currScore, helper(words, start + 1,
                              letterCounts,
                              score));
 
        // Return the maximum score
        return currScore;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        // Given arrays
        String words[] = { "dog", "cat", "dad", "good" };
        char letters[] = { 'a', 'a', 'c', 'd', 'd',
                           'd', 'g', 'o', 'o' };
        int score[]
            = { 1, 0, 9, 5, 0, 0, 3, 0, 0, 0, 0, 0, 0,
                0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
        // Function Call
        System.out.println(
            maxScoreWords(words, letters, score));
    }
}


C#
// C# program for the above approach
using System;
using System.Linq;
 
class GFG
{
 
    // Function to find the maximum cost
    // of any valid set of words formed
    // by using the given letters
    public static int maxScoreWords(
        string[] words, char[] letters,
        int[] score)
    {
       
        // Stores frequency of characters
        int[] letterCounts = new int[26];
 
        foreach (char letter in letters)
            letterCounts[letter - 'a']++;
 
        // Find the maximum cost
        return helper(words, 0,
                      letterCounts,
                      score);
    }
 
    // Utility function to find
    // maximum cost of generating
    // any possible subsets of strings
    public static int helper(
        string[] words, int start,
        int[] letterCounts, int[] score)
    {
       
        // Base Case
        if (start == words.Length)
            return 0;
 
        // Stores the current cost
        int currScore = 0;
 
        // Stores the cost of
        // by the current word
        int wordScore = 0;
 
        // Create a copy of the
        // letterCounts array
        int[] nextCounts
            = letterCounts.ToArray();
 
        // Traverse the current word
        for (int i = 0;
             i < words[start].Length;
             ++i) {
 
            // Store the current index & check
            // if its frequency is 0 or not
            int idx = words[start][i] - 'a';
 
            if (nextCounts[idx] == 0) {
 
                // If true, then update
                // wordScore to -1
                wordScore = -1;
                break;
            }
 
            // Otherwise, add the cost of
            // the current index to wordScore
            wordScore += score[idx];
 
            // Decrease its frequency
            nextCounts[idx]--;
        }
 
        // If wordScore > 0, then
        // recursively call for next index
        if (wordScore > 0)
            currScore = helper(words,
                               start + 1,
                               nextCounts,
                               score)
                        + wordScore;
 
        // Find the cost by not
        // including current word
        currScore = Math.Max(
            currScore, helper(words, start + 1,
                              letterCounts,
                              score));
 
        // Return the maximum score
        return currScore;
    }
 
    // Driver Code
    public static void Main(string[] args)
    {
       
        // Given arrays
        string []words = { "dog", "cat", "dad", "good" };
        char []letters = { 'a', 'a', 'c', 'd', 'd',
                           'd', 'g', 'o', 'o' };
        int []score
            = { 1, 0, 9, 5, 0, 0, 3, 0, 0, 0, 0, 0, 0,
                0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
        // Function Call
        Console.WriteLine(
            maxScoreWords(words, letters, score));
    }
}
 
// This code is contributed by ukasp.


Java
// Java program for the above approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    // Function to find the maximum cost
    // of any valid set of words formed
    // by using the given letters
    public static int maxScoreWords(
        String[] words, char[] letters,
        int[] score)
    {
        // Stores frequency of characters
        int[] letterCounts = new int[26];
 
        for (char letter : letters)
            letterCounts[letter - 'a']++;
 
        // Function Call to find the
        // maximum cost
        return helper(words, 0, letterCounts,
                      score,
                      new HashMap<>());
    }
 
    // Utility function to find maximum
    // cost of generating any possible
    // subsets of strings
    public static int helper(
        String[] words, int start,
        int[] letterCounts, int[] score,
        Map memo)
    {
        // Base Case
        if (start == words.length)
            return 0;
 
        // If the score for this call
        // is already computed,    then
        // return result from hashmap
        String key = getKey(letterCounts, start);
 
        if (memo.containsKey(key))
            return memo.get(key);
 
        // Store the current score
        int currScore = 0;
 
        // Stores the cost contributed
        // by the current word
        int wordScore = 0;
 
        // Create a copy of the
        // letterCounts array
        int[] nextCounts = letterCounts.clone();
 
        // Traverse the current word
        // i.e., words[start]
        for (int i = 0;
             i < words[start].length();
             ++i) {
 
            // Store the current index
            // & check if its frequency
            // is 0 or not
            int idx = words[start].charAt(i) - 'a';
 
            if (nextCounts[idx] == 0) {
 
                // If true, then update
                // wordScore to -1 and
                // break
                wordScore = -1;
                break;
            }
 
            // Otherwise, add the cost
            // of the current index to
            // wordScore and decrease
            // its frequency
            wordScore += score[idx];
            nextCounts[idx]--;
        }
 
        // If wordScore > 0, then
        // recursively call for the
        // next index
        if (wordScore > 0)
            currScore = helper(words, start + 1,
                               nextCounts,
                               score, memo)
                        + wordScore;
 
        // Find the cost by not including
        // the current word
        currScore = Math.max(
            currScore, helper(words, start + 1,
                              letterCounts, score,
                              memo));
 
        // Memoize the result
        memo.put(key, currScore);
 
        // Return the maximum score
        return currScore;
    }
 
    // Function to get the unique key
    // from the  letterCounts array
    // with their index
    public static String getKey(
        int[] letterCounts, int idx)
    {
        // Append the frequency of
        // each character
        StringBuilder sb = new StringBuilder();
 
        for (int i = 0; i < 26; ++i)
            sb.append(letterCounts[i]);
 
        // Append the index
        sb.append(', ');
        sb.append(idx);
 
        // Return the string
        return sb.toString();
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        String words[] = { "dog", "cat", "dad", "good" };
        char letters[] = { 'a', 'a', 'c', 'd', 'd',
                           'd', 'g', 'o', 'o' };
        int score[]
            = { 1, 0, 9, 5, 0, 0, 3, 0, 0, 0, 0, 0, 0,
                0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
        System.out.println(
            maxScoreWords(words, letters,
                          score));
    }
}


输出:
23

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

高效方法:通过观察上述问题具有最优子结构和重叠子问题的事实,也可以优化上述方法。因此,其思想是记住每个递归调用中的结果,并在执行相同的递归调用时使用那些存储的状态。为了存储每个递归调用,请使用HashMap。

下面是上述方法的实现:

Java

// Java program for the above approach
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    // Function to find the maximum cost
    // of any valid set of words formed
    // by using the given letters
    public static int maxScoreWords(
        String[] words, char[] letters,
        int[] score)
    {
        // Stores frequency of characters
        int[] letterCounts = new int[26];
 
        for (char letter : letters)
            letterCounts[letter - 'a']++;
 
        // Function Call to find the
        // maximum cost
        return helper(words, 0, letterCounts,
                      score,
                      new HashMap<>());
    }
 
    // Utility function to find maximum
    // cost of generating any possible
    // subsets of strings
    public static int helper(
        String[] words, int start,
        int[] letterCounts, int[] score,
        Map memo)
    {
        // Base Case
        if (start == words.length)
            return 0;
 
        // If the score for this call
        // is already computed,    then
        // return result from hashmap
        String key = getKey(letterCounts, start);
 
        if (memo.containsKey(key))
            return memo.get(key);
 
        // Store the current score
        int currScore = 0;
 
        // Stores the cost contributed
        // by the current word
        int wordScore = 0;
 
        // Create a copy of the
        // letterCounts array
        int[] nextCounts = letterCounts.clone();
 
        // Traverse the current word
        // i.e., words[start]
        for (int i = 0;
             i < words[start].length();
             ++i) {
 
            // Store the current index
            // & check if its frequency
            // is 0 or not
            int idx = words[start].charAt(i) - 'a';
 
            if (nextCounts[idx] == 0) {
 
                // If true, then update
                // wordScore to -1 and
                // break
                wordScore = -1;
                break;
            }
 
            // Otherwise, add the cost
            // of the current index to
            // wordScore and decrease
            // its frequency
            wordScore += score[idx];
            nextCounts[idx]--;
        }
 
        // If wordScore > 0, then
        // recursively call for the
        // next index
        if (wordScore > 0)
            currScore = helper(words, start + 1,
                               nextCounts,
                               score, memo)
                        + wordScore;
 
        // Find the cost by not including
        // the current word
        currScore = Math.max(
            currScore, helper(words, start + 1,
                              letterCounts, score,
                              memo));
 
        // Memoize the result
        memo.put(key, currScore);
 
        // Return the maximum score
        return currScore;
    }
 
    // Function to get the unique key
    // from the  letterCounts array
    // with their index
    public static String getKey(
        int[] letterCounts, int idx)
    {
        // Append the frequency of
        // each character
        StringBuilder sb = new StringBuilder();
 
        for (int i = 0; i < 26; ++i)
            sb.append(letterCounts[i]);
 
        // Append the index
        sb.append(', ');
        sb.append(idx);
 
        // Return the string
        return sb.toString();
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        String words[] = { "dog", "cat", "dad", "good" };
        char letters[] = { 'a', 'a', 'c', 'd', 'd',
                           'd', 'g', 'o', 'o' };
        int score[]
            = { 1, 0, 9, 5, 0, 0, 3, 0, 0, 0, 0, 0, 0,
                0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
        System.out.println(
            maxScoreWords(words, letters,
                          score));
    }
}
输出:
23

时间复杂度: O(N * X),其中X是words []数组中最大字符串的大小。
辅助空间: O(N)