通过为每个字符分配 [1, 26] 范围内的值来最大化字符串值

data structurec++server side programmingprogramming

英语中总共有 26 种不同的字母。如果我们想将字母转换为数值,则只需为字母分配 1 到 26 之间的值。

现在,在这个问题中,我们需要通过为每个字符分配 [1, 26] 范围内的值来最大化字符串值。让我们看看如何解决这个问题。

让我们借助一些示例来理解这个问题。

输入 - s = "blpsBpPtT"

输出 - 221

解释 - 在本题中,为了最大化给定字符串的值,我们将 -

  • 26 赋给 p,P

  • 25 赋给 b,B

  • 24 赋给 t,T

  • 23 赋给 l

  • 22 赋给 s

因此,净输出将变为 ((26 * 3) + (25 * 2) + (24 * 2) + (23 * 1) + (22 * 1)) 等于 221。

输入 − s = "Aa$#&*@!Bsbb"

输出 − 152

解释 − 在本题中,为了最大化给定字符串的值,我们将赋值给 −

  • 26 赋给 b,B

  • 25 赋给 a,A

  • 24 赋给 s

  • 其余字符的值如果为零,则不会获得任何值

因此,净输出将变为 ((26 * 3) + (25 * 2) + (24 * 1)),等于 152。

问题解释

让我们尝试理解这个问题并找到它的解决方案。在这个问题中,如果字符是字母,我们需要通过分配一个从 1 到 26 的值来最大化字符串的值;如果它不是字母,对于任何其他字符,例如"$"、"#"、"&" 等,我们将该值视为零。对于大写字母和小写字母,如果它们属于同一类型,则我们认为它们相同,也就是说,"p"和"P"将被视为相似。我们可以通过为出现频率最高的字母字符分配最大值来快速最大化数字。在下一篇文章中,有两种存储频率的方法,我们很快就会看到这两种方法。

解决方案 1 使用 Map

算法

  • 定义一个 Map,例如 m。

  • 运行一个循环,将给定字符串中大写和小写字母的字符频率存储在 Map 中。

  • 将频率推送到向量中

  • 对包含频率的向量进行排序

  • 从后往前依次将频率乘以 26、25、24,依此类推,直到 1

  • 将相乘后的值相加即可得到最终答案。

C++ 代码实现示例

#include <bits/stdc++.h>
using namespace std;
// 函数通过为每个字符分配 [1, 26] 范围内的值来最大化字符串值
int Helper(string s){
    // 定义一个映射来存储字符,以计算每个字符的频率
	map<int,int>m;
	// 运行循环来初始化映射
	for (int i=0;i<s.size();i++){
	   char chr=s[i];
		// 存储小写字符
		if (chr >= 'a' && chr <= 'z') {
			m[chr - 'a']++;
		}
		// 存储大写字符
		else if (chr >= 'A' && chr <= 'Z') {
			m[chr - 'A']++;
		}
	}
	vector<int>v;
    // 将频率推送到向量中
    for(auto a:m){
        v.push_back(a.second);
    }
    // 对频率进行排序
    sort(v.begin(),v.end());
    // 初始化 ans 变量
    int ans=0, num=26;
    // 根据频率和范围 [1, 26] 获取答案
	for(int i=v.size()-1; i>=0; i--){
        // 将最高频率与 num 相加,num 初始设置为 26
        ans+=(num*v[i]);
        // 减少 num 以移动到下一个最大频率
        num--;
	}
	// 返回最终输出
	return ans;
}
int main(){
   // 给出输入字符串
   string S = "aBAbgha";
   // Call the helper function to maximize the String value by assigning values in the range [1, 26] to each character
   cout << "通过为每个字符分配范围 [1, 26] 内的值,最大的字符串值为: "<<Helper(S);
   return 0;
}

输出

通过为每个字符分配范围 [1, 26] 内的值,最大的字符串值为: 175

上述代码的复杂度

  • 时间复杂度 - O(n*(log(n)));这里我们使用了循环,但它们会运行"n"次,然而,排序函数将花费 (n * log(n)) 的时间来执行,因此我们将代码的总体复杂度设为 n * log(n)。

  • 空间复杂度 - O(26);因为英语中只有 26 种不同的字母。

解决方案 2:使用频率向量

算法

  • 定义一个向量,例如 v,大小为 26,所有初始值均为 0

  • 运行一个循环,将给定字符串中大写和小写字母的字符频率存储在该向量中,现在称为频率向量

  • 对包含频率的向量进行排序

  • 从后往前依次将频率乘以 26、25、24,直至 1,当频率达到 0 时,终止循环

  • 将相乘后的值相加即可得到最终答案

C++ 代码示例

实施
#include <bits/stdc++.h>
using namespace std;
// 函数通过为每个字符分配 [1, 26] 范围内的值来最大化字符串值
int Helper(string s){
    // 定义一个大小为 26 的频率向量,初始元素为 0
	vector<int> v(26, 0);
	// 运行循环来初始化向量
	for (int i=0;i<s.size();i++){
	    char chr=s[i];
		// 存储小写字符
		if (chr >= 'a' && chr <= 'z') {
			v[chr - 'a']++;
		}
		// 存储大写字符
		else if (chr >= 'A' && chr <= 'Z') {
			v[chr - 'A']++;
		}
	}
    // 对向量进行排序
    sort(v.begin(), v.end());
    // 初始化答案变量
    int ans = 0;
    // 根据频率和范围 [1, 26] 获取答案
	for (int i = 25; i >= 0; i--) {
		// 检查频率值是否为 0,如果为 0,则停止循环
		if (v[i] == 0) {
			break;
		}
		else{
		    // 将最高频率与初始设置为 26 的数字相加
		    ans+=v[i] * (i + 1);
		}
	}
	// 返回获得的最大和
	return ans;
}
int main(){
   // 给出输入字符串
   string S = "aBAbgha";
   // 调用辅助函数,通过为每个字符分配 [1, 26] 范围内的值来最大化字符串值
   cout << "通过为每个字符分配范围 [1, 26] 内的值,最大的字符串值为: "<<Helper(S);
   return 0;
}

输出

通过为每个字符分配范围 [1, 26] 内的值,最大的字符串值为: 175

上述代码的复杂度

  • 时间复杂度 - O(n*(log(n)));这里我们使用了循环,但它们会运行"n"次,然而,排序函数需要 (n * log(n)) 的时间来执行,因此我们将代码的总体复杂度设为 n * log(n)。

  • 空间复杂度 - O(26);因为英语中只有 26 种不同的字母表。

注意 - 上述方法使用频率向量,而不是将频率存储在映射中。

结论

在本文中,为了通过为每个字符分配 [1, 26] 范围内的值来最大化字符串值,我们将采用两种方法来存储每个元素的频率。在第一种方法中,我们将使用映射来存储每个字母表的频率,无论字母表是小写还是大写。然而,在第二种方法中,我们可以避免映射占用的额外空间,而可以直接使用频率向量。


相关文章