【贪心 堆 】3081. 替换字符串中的问号使分数最小

简介: 【贪心 堆 】3081. 替换字符串中的问号使分数最小

算法可以发掘本质,如:

一,若干师傅和徒弟互有好感,有好感的师徒可以结对学习。师傅和徒弟都只能参加一个对子。如何让对子最多。

二,有无限多1X2和2X1的骨牌,某个棋盘若干格子坏了,如何在没有坏的格子放足够多骨牌。

三,某个单色图,1表示前前景,0表示后景色。每次操作可以将一个1,变成0。如何在最少得操作情况下,使得没有两个1相邻(四连通)。

四,若干路人,有些人是熟人,如何选出最多的人参加实验。为了避免熟人影响实验的效果,参加的人不能是熟人。

一二是二分图的最大匹配,三是二分图的最小点覆盖,四是二分图最大独立集。 而这三者是等效问题。

本文涉及知识点

贪心 堆

LeetCode 3081. 替换字符串中的问号使分数最小

给你一个字符串 s 。s[i] 要么是小写英文字母,要么是问号 ‘?’ 。

对于长度为 m 且 只 含有小写英文字母的字符串 t ,我们定义函数 cost(i) 为下标 i 之前(也就是范围 [0, i - 1] 中)出现过与 t[i] 相同 字符出现的次数。

字符串 t 的 分数 为所有下标 i 的 cost(i) 之 和 。

比方说,字符串 t = “aab” :

cost(0) = 0

cost(1) = 1

cost(2) = 0

所以,字符串 “aab” 的分数为 0 + 1 + 0 = 1 。

你的任务是用小写英文字母 替换 s 中 所有 问号,使 s 的 分数最小 。

请你返回替换所有问号 ‘?’ 之后且分数最小的字符串。如果有多个字符串的 分数最小 ,那么返回字典序最小的一个。

示例 1:

输入:s = “???”

输出: “abc”

解释:这个例子中,我们将 s 中的问号 ‘?’ 替换得到 “abc” 。

对于字符串 “abc” ,cost(0) = 0 ,cost(1) = 0 和 cost(2) = 0 。

“abc” 的分数为 0 。

其他修改 s 得到分数 0 的字符串为 “cba” ,“abz” 和 “hey” 。

这些字符串中,我们返回字典序最小的。

示例 2:

输入: s = “a?a?”

输出: “abac”

解释:这个例子中,我们将 s 中的问号 ‘?’ 替换得到 “abac” 。

对于字符串 “abac” ,cost(0) = 0 ,cost(1) = 0 ,cost(2) = 1 和 cost(3) = 0 。

“abac” 的分数为 1 。

提示:

1 <= s.length <= 105

s[i] 要么是小写英文字母,要么是 ‘?’ 。

贪心

令各字母最多出现m次。

n个相同的字母,贡献的分数是: (n-1)+ (n-2)⋯ \cdots + n + 1 = n *(n-1)/2 ,和n的平方有关。

显然每个?都替换当前最少的字符,如果相等则替换最小的字符。

性质一:替换出现次数少的是局部最优解

假定两个字母分别出现了a 次,b次。

方法一:?变a。

方法二:?变b。

方案一:(a+1)a/2 + b(b-1)/2

方案二:a*(a-1)/2 + (b+1)b/2
方案一
2 : a2+a + b2-b

方案二*2:a2-a + b2 +b

两者相减: 2(a-b)

image.png

证明一:不能将所有字符全部换到m个

对于任意a < b。 假定在a

证明二:能全部换成m个

所有字符出现次数只会是x1和x1+1。如果有数c小于x,则不然有数d大于等于x+1。

c++,d–,会更优。

代码

核心代码

class Solution {
public:
  string minimizeStringValue(string s) {
    int cnt[26] = { 0 };
    int star = 0;
    for (const auto& ch : s) {
      if ('?' == ch) {
        star++;
      }
      else
      {
        cnt[ch - 'a']++;
      }
    }
    std::priority_queue<pair<int,int>, vector<pair<int, int>>, greater<>> minHeap;
    for (int i = 0; i < 26; i++) {
      minHeap.emplace(make_pair(cnt[i],i));
    }
    while (star > 0) {
      auto [cnt,i1] = minHeap.top();
      minHeap.pop();
      minHeap.emplace(make_pair(cnt + 1,i1));
      star--;
    }
    int cnt2[26] = { 0 };
    while (minHeap.size()) {
      auto [iCnt, i1] = minHeap.top();
      minHeap.pop();
      cnt2[i1] = iCnt - cnt[i1];
    }
    for (int i = 0, j = 0; i < s.length(); i++) {
      if ('?' != s[i]) { continue; }
      while (0 == cnt2[j]) {
        j++;
      }
      cnt2[j]--;
      s[i] = j + 'a';
    }
    return s;
  }
};

测试用例

int main()
{ 
  string s;
  {
    Solution sln;
    s = "???";
    auto res = sln.minimizeStringValue(s);
    Assert(string("abc"), res);
  }
  {
    Solution sln;
    s = "a?a?";
    auto res = sln.minimizeStringValue(s);
    Assert(string("abac"), res);
  }
  
}


我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。


相关文章
|
NoSQL Linux Redis
Redis内存分析工具RDR
感觉开发越是做到后面,除了对程序本身的理解;更多的是对工具的了解和运用,了解不同的工具的作用,对开发效率以及问题的快速定位,都有一个质的飞越。 背景是这样子的,我们有个业务需要对大量数据进行实时分析,底层服务一直不太稳定,内存以及cpu占用都非高,大量占用系统资源;由于数据量大,之前负责的同事也一直没有找到好的方法,单纯的依靠人力去分析代码,搞了挺长时间也没有根本性的解决问题,总是治标不治本。
1104 0
Redis内存分析工具RDR
|
弹性计算 数据可视化 关系型数据库
【最佳实践】Filebeat实现MySQL日志轻量化发送至Elasticsearch
在今天的文章中,我们来详细地描述如果使用Filebeat把MySQL的日志信息传输到Elasticsearch中。
4659 0
【最佳实践】Filebeat实现MySQL日志轻量化发送至Elasticsearch
|
消息中间件 运维 算法
Kafka 为什么要抛弃 Zookeeper?
本文探讨了Kafka为何逐步淘汰ZooKeeper。长久以来,ZooKeeper作为Kafka的核心组件,负责集群管理和协调任务。然而,随着Kafka的发展,ZooKeeper带来的复杂性增加、性能瓶颈及一致性问题日益凸显。为解决这些问题,Kafka引入了KRaft,这是一种基于Raft算法的内置元数据管理方案,不仅简化了部署流程,还提升了系统的一致性和扩展性。本文详细分析了这一转变背后的原因及其带来的优势,并展望了Kafka未来的发展方向。
768 1
|
关系型数据库 MySQL 测试技术
如何进行数据库的升级?
【7月更文挑战第21天】如何进行数据库的升级?
912 1
遇到Error saving license data.C:\Users|yyh\idea.key(拒绝访问。) CORP\AppDatalRoamingVetBrainslIntellilldea20的解决思路
今日进行云桌面迁移后,发现已激活的IDEA软件失效,并且每次启动都需要重新激活,极为不便。经过一番调查与尝试多种解决方案后,最终通过第4种方法解决了问题:先进入特定设置界面移除原有激活信息,再重新输入激活码完成激活过程,从而确保下次启动不再需要重复激活步骤。
|
机器学习/深度学习 PyTorch 算法框架/工具
深度学习实践篇 第五章:模型保存与加载
简要介绍pytorch中模型的保存与加载。
554 0
|
JSON 数据可视化 定位技术
可视化 | Python绘制高颜值台风地理轨迹图
可视化 | Python绘制高颜值台风地理轨迹图
|
存储 算法 Java
虚拟机中的经典垃圾收集器及常用参数解析(Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1)
这里说的经典垃圾收集器,并不是说这些垃圾收集器多么的优秀,因为随着JDK版本的不断更新,新的垃圾收集器越来越多,这些在JDK9及之前使用的垃圾收集器自然就成为了相对经典的版本。说到垃圾收集器,就必须说垃圾收集算法 点击查看垃圾收集算法详解 ,因为垃圾收集算法是收集收集器的方法论,正是因为有了垃圾收集算法,才有了各种各样的垃圾收集器,下面认识下这些经典的垃圾收集器吧。
1132 0
虚拟机中的经典垃圾收集器及常用参数解析(Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1)
|
Kubernetes Shell Perl
文档解读 | K8S中的Pod和容器配置(一)
如何给运行在Kubernetes(K8S) Pod中的容器定义环境变量、命令行和参数? 给运行在Kubernetes Pod中的容器定义环境变量 开始之前 必须有一个Kubernets集群,和一个能和集群沟通的kubectl命令行工具。
5936 0