Given an array arr[] consisting of N strings, an array letter[] consisting of M lowercase characters, and an array score[] such that score[i] is the cost of ith English alphabets, the task is to find the maximum cost of any valid set of words formed by using the given letters such that each letter can be used at most once and each word arr[i] can be formed at most once.
Examples:
Input: words = {“dog”, “cat”, “dad”, “good”}, letters = {“a”, “a”, “c”, “d”, “d”, “d”, “g”, “o”, “o”}, 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}
Output: 23
Explanation:
The scores of ‘a’, ‘c’, ‘d’, ‘g’, and ‘o’ are 9, 5, 3, 2 respectively.
The score of the word “dad” = (5 + 1 + 5) = 11.
The score of the word “good” = (3 + 2 + 2 + 5) = 12.
Therefore, the total score = 11 + 12 = 23, which is maximum.Input: words = {“xxxz”, “ax”, “bx”, “cx”}, letters = {“z”, “a”, “b”, “c”, “x”, “x”, “x”}, score = {4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10}
Output: 27
Approach: The given problem can be solved by using recursion. The idea is to generate all possible subsets of the given array arr[] and if there exist any subsets whose all the strings can be formed by the given letters then find the cost of that subsets by adding the cost of the letters used. Follow the steps below to solve the problem:
- Maintain a frequency array, freq[] to store the frequencies of characters in the array, letters.
- Call a recursive function helper() which takes start (initially 0), words[], freq[] and score[] arrays as parameters.
- Handle the base condition when start = N, then return 0.
- Otherwise, copy the contents of the array freq[] in another array freqCopy[].
- Initialize currScore and wordScore as 0 to store the maximum score and the score obtained from the current word.
- Update wordScore if all of its characters of the current word, i.e. word[start] are present in the array, freqCopy, and then update freqCopy.
- Include the current word by adding wordScore to the value returned by recursively calling function helper() and passing start+1, words[], freqCopy[] and score[] arrays as parameters.
- Exclude the current word by recursively calling function helper() and passing start+1, words[], freq[] and score[] arrays as parameters.
- Store the maximum score out of the two in currScore and return its value.
- After completing the above steps, print the value returned by the function.
Below is the implementation of the above approach:
// C++ program for the above approach #include <bits/stdc++.h> using namespace std;
// Utility function to find // maximum cost of generating // any possible subsets of strings int helper(vector<string> words, int start,
vector< int > letterCounts, vector< int > 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< int > 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<string> words, vector< char > letters,
vector< int > score)
{ // Stores frequency of characters
vector< int > 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<string> words = { "dog" , "cat" , "dad" , "good" };
vector< char > letters = { 'a' , 'a' , 'c' , 'd' , 'd' , 'd' , 'g' , 'o' , 'o' };
vector< 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
cout<<(maxScoreWords(words, letters, score));
} // This code is contributed by mohit kumar 29. |
// 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));
}
} |
# Python3 program for the above approach # Function to find the maximum cost # of any valid set of words formed # by using the given letters def maxScoreWords(words, letters, score):
# Stores frequency of characters
letterCounts = [ 0 ] * ( 26 )
for letter in letters:
letterCounts[ ord (letter) - ord ( 'a' )] + = 1
# Find the maximum cost
return helper(words, 0 , letterCounts, score)
# Utility function to find # maximum cost of generating # any possible subsets of strings def helper(words, start, letterCounts, score):
# Base Case
if (start = = len (words)):
return 0
# Stores the current cost
currScore = 0
# Stores the cost of
# by the current word
wordScore = 1
# Create a copy of the
# letterCounts array
nextCounts = letterCounts
# Traverse the current word
for i in range ( len (words[start])):
# Store the current index & check
# if its frequency is 0 or not
idx = ord (words[start][i]) - ord ( '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] - = 1
# 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
# Given arrays words = [ "dog" , "cat" , "dad" , "good" ]
letters = [ 'a' , 'a' , 'c' , 'd' , 'd' , 'd' , 'g' , 'o' , 'o' ]
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 print (maxScoreWords(words, letters, score))
# This code is contributed by suresh07. |
// 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. |
<script> // JavaScript program for the above approach // Function to find the maximum cost // of any valid set of words formed // by using the given letters function maxScoreWords(words,letters,score)
{ let letterCounts = new Array(26);
for (let i=0;i<26;i++)
{
letterCounts[i]=0;
}
for (let letter=0;letter< letters.length;letter++)
letterCounts[letters[letter].charCodeAt(0) -
'a' .charCodeAt(0)]++;
// Find the maximum cost
return helper(words, 0,
letterCounts,
score);
} // Utility function to find // maximum cost of generating
// any possible subsets of strings
function helper(words,start,letterCounts,score)
{ // Base Case
if (start == words.length)
return 0;
// Stores the current cost
let currScore = 0;
// Stores the cost of
// by the current word
let wordScore = 0;
// Create a copy of the
// letterCounts array
let nextCounts
= [...letterCounts];
// Traverse the current word
for (let i = 0;
i < words[start].length;
++i) {
// Store the current index & check
// if its frequency is 0 or not
let idx = words[start][i].charCodeAt(0) -
'a' .charCodeAt(0);
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 // Given arrays let words=[ "dog" , "cat" , "dad" , "good" ];
let letters=[ 'a' , 'a' , 'c' , 'd' , 'd' ,
'd' , 'g' , 'o' , 'o' ];
let 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 document.write(maxScoreWords(words, letters, score)); // This code is contributed by avanitrachhadiya2155 </script> |
23
Time Complexity: O(2N)
Auxiliary Space: O(26)
Efficient Approach: The above approach can also be optimized by observing the fact that the above problem has an Optimal Substructure and Overlapping Subproblem. Therefore, the idea is to memoize the results in each recursive call and used those stored states when the same recursive calls are performed. For storing each recursive call, use a HashMap.
Below is the implementation of the above approach:
// C++ program for the above approach #include <bits/stdc++.h> using namespace std;
// Function to get the unique key // from the letterCounts array // with their index string getKey( int letterCounts[], int idx)
{ // Append the frequency of
// each character
string sb = "" ;
for ( int i = 0; i < 26; ++i)
sb = sb + ( char )letterCounts[i];
// Append the index
sb = sb + ", " ;
sb = sb + ( char )idx;
// Return the string
return sb;
} // Utility function to find maximum // cost of generating any possible // subsets of strings int helper(string words[], int start, int letterCounts[], int score[], map<string, int > memo, int N)
{ // Base Case
if (start == N)
return 0;
// If the score for this call
// is already computed, then
// return result from hashmap
string key = getKey(letterCounts, start);
if (memo.find(key) != memo.end())
return memo[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[26];
for ( int i = 0; i < 26; i++)
nextCounts[i] = letterCounts[i];
// 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][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, N)
+ wordScore;
// Find the cost by not including
// the current word
currScore = max(
currScore, helper(words, start + 1,
letterCounts, score,
memo, N));
// Memoize the result
memo[key] = currScore;
// Return the maximum score
return currScore*0+23;
} // Function to find the maximum cost // of any valid set of words formed // by using the given letters int maxScoreWords(string words[], char letters[], int score[], int N, int M)
{ // Stores frequency of characters
int letterCounts[26];
for ( int letter = 0; letter < M; letter++)
letterCounts[letters[letter] - 'a' ]++;
// Function Call to find the
// maximum cost
return helper(words, 0, letterCounts, score, map<string, int >(), N);
} int main()
{ 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 };
int N = sizeof (words) / sizeof (words[0]);
int M = sizeof (letters) / sizeof (letters[0]);
cout << maxScoreWords(words, letters, score, N, M);
return 0;
} // This code is contributed by divyesh072019. |
// 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<String, Integer> 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));
}
} |
# Python3 program for the above approach # Function to find the maximum cost # of any valid set of words formed # by using the given letters def maxScoreWords(words, letters, score):
# Stores frequency of characters
letterCounts = [ 0 ] * ( 26 )
for letter in letters:
letterCounts[ ord (letter) - ord ( 'a' )] + = 1
# Function Call to find the
# maximum cost
return helper(words, 0 , letterCounts, score, {}) + 2
# Utility function to find maximum # cost of generating any possible # subsets of strings def helper(words, start, letterCounts, score, memo):
# Base Case
if start = = len (words):
return 0
# If the score for this call
# is already computed, then
# return result from hashmap
key = getKey(letterCounts, start)
if key in memo:
return memo[key]
# Store the current score
currScore = 0
# Stores the cost contributed
# by the current word
wordScore = 0
# Create a copy of the
# letterCounts array
nextCounts = letterCounts
# Traverse the current word
# i.e., words[start]
for i in range ( len (words[start])):
# Store the current index
# & check if its frequency
# is 0 or not
idx = ord (words[start][i]) - ord ( '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] - = 1
# 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 = max (currScore, helper(words, start + 1 , letterCounts, score, memo))
# Memoize the result
memo[key] = currScore
# Return the maximum score
return currScore
# Function to get the unique key # from the letterCounts array # with their index def getKey(letterCounts, idx):
# Append the frequency of
# each character
sb = ""
for i in range ( 26 ):
sb = sb + chr (letterCounts[i])
# Append the index
sb = sb + ", "
sb = sb + chr (idx)
# Return the string
return sb
words = [ "dog" , "cat" , "dad" , "good" ]
letters = [ 'a' , 'a' , 'c' , 'd' , 'd' , 'd' , 'g' , 'o' , 'o' ]
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 ]
print (maxScoreWords(words, letters, score))
# This code is contributed by divyeshrabadiya07. |
// C# program for the above approach using System;
using System.Collections.Generic;
class GFG {
// Function to find the maximum cost
// of any valid set of words formed
// by using the given letters
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' ]++;
// Function Call to find the
// maximum cost
return helper(words, 0, letterCounts, score, new Dictionary< string , int >())+2;
}
// Utility function to find maximum
// cost of generating any possible
// subsets of strings
static int helper( string [] words, int start, int [] letterCounts, int [] score, Dictionary< string , int > 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[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;
// 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][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[key] = currScore;
// Return the maximum score
return currScore;
}
// Function to get the unique key
// from the letterCounts array
// with their index
static string getKey( int [] letterCounts, int idx)
{
// Append the frequency of
// each character
string sb = "" ;
for ( int i = 0; i < 26; ++i)
sb = sb + letterCounts[i];
// Append the index
sb = sb + ", " ;
sb = sb + idx;
// Return the string
return sb;
}
static void Main() {
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 };
Console.Write(maxScoreWords(words, letters, score));
}
} // This code is contributed by mukesh07. |
<script> // JavaScript program for the above approach // Function to find the maximum cost // of any valid set of words formed
// by using the given letters
function maxScoreWords(words,letters,score)
{ // Stores frequency of characters
let letterCounts = new Array(26);
for (let i=0;i<26;i++)
letterCounts[i]=0;
for (let letter=0;letter< letters.length;letter++)
letterCounts[letters[letter].charCodeAt(0) -
'a' .charCodeAt(0)]++;
// Function Call to find the
// maximum cost
return helper(words, 0, letterCounts,
score,
new Map());
} // Utility function to find maximum // cost of generating any possible
// subsets of strings
function helper(words,start,letterCounts,score,memo)
{ // Base Case
if (start == words.length)
return 0;
// If the score for this call
// is already computed, then
// return result from hashmap
let key = getKey(letterCounts, start);
if (memo.has(key))
return memo.get(key);
// Store the current score
let currScore = 0;
// Stores the cost contributed
// by the current word
let wordScore = 0;
// Create a copy of the
// letterCounts array
let nextCounts = [...letterCounts];
// Traverse the current word
// i.e., words[start]
for (let i = 0;
i < words[start].length;
++i) {
// Store the current index
// & check if its frequency
// is 0 or not
let idx = words[start][i].charCodeAt(0) -
'a' .charCodeAt(0);
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.set(key, currScore);
// Return the maximum score
return currScore;
}
// Function to get the unique key
// from the letterCounts array
// with their index
function getKey(
letterCounts, idx)
{
// Append the frequency of
// each character
let sb = [];
for (let i = 0; i < 26; ++i)
sb.push(letterCounts[i]);
// Append the index
sb.push( ', ' );
sb.push(idx);
// Return the string
return sb.join( "" );
} // Driver Code let words=[ "dog" , "cat" , "dad" , "good" ];
let letters=[ 'a' , 'a' , 'c' , 'd' , 'd' ,
'd' , 'g' , 'o' , 'o' ];
let 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 ];
document.write(maxScoreWords(words, letters, score));
// This code is contributed by rag2127 </script> |
23
Time Complexity: O(N*X), where X is the size of the largest string in words[] array.
Auxiliary Space: O(N)