当前位置: 首页 > news >正文

leetcode:最小覆盖字符串

1笨方法

对于算法题目,自己能想到的往往是最基础的笨方法。

代码如下:

如果t的长度是len1,s的长度是len2,那么最小窗口是len1,最大窗口是len2。所以可以从len1到len2,遍历窗口大小,对于每个窗口大小,将窗口从前向后进行移动。因为窗口是从小到大进行遍历,所以第一次遇到满足条件的子串时,就可以直接返回。这种算法的时间复杂度是O(n*n),在leetcode上运行会超时。

class Solution { public: string minWindow(string s, string t) { std::map<char, int> tConstMap; std::map<char, int> tTmpMap; for (char c : t) { if (tConstMap.count(c) > 0) { tConstMap[c]++; } else { tConstMap[c] = 1; } tTmpMap[c] = 0; } int minWindow = t.size(); int maxWindow = s.size(); int maxLength = s.size(); for (int window = minWindow; window <= maxWindow; window++) { for (int i = 0; i <= maxLength - window; i++) { for (int j = i; j < i + window; j++) { if (tConstMap.count(s[j]) > 0) { tTmpMap[s[j]]++; } } bool result = true; for (auto [c, count] : tTmpMap) { if(count < tConstMap[c]) { result = false; } tTmpMap[c] = 0; } if (result == true) { std::cout << "i:" << i <<",window:" << window <<std::endl; return s.substr(i, window); } } } return ""; } };

针对上边的代码,我们可以看到,针对一个确定大小的window,在从前向后遍历的过程中,每次只移动了一个字符的位置,但是每次都要对tTmpMap进行清空并重新计算,完全可以只对移出窗口的元素和移入窗口的元素进行处理。但是时间复杂度仍然较高,在leetcode上运行会超时。

class Solution { public: string minWindow(string s, string t) { std::map<char, int> tConstMap; std::map<char, int> tTmpMap; for (char c : t) { if (tConstMap.count(c) > 0) { tConstMap[c]++; } else { tConstMap[c] = 1; } tTmpMap[c] = 0; } int minWindow = t.size(); int maxWindow = s.size(); int maxLength = s.size(); for (int window = minWindow; window <= maxWindow; window++) { for (int i = 0; i <= maxLength - window; i++) { if (i == 0) { for (auto [c, value] : tTmpMap) { tTmpMap[c] = 0; } for (int j = i; j < i + window; j++) { if (tConstMap.count(s[j]) > 0) { tTmpMap[s[j]]++; } } } else { if (tConstMap.count(s[i +window - 1]) > 0) { tTmpMap[s[i +window - 1]]++; } } bool result = true; for (auto [c, count] : tTmpMap) { if(count < tConstMap[c]) { result = false; break; } } if (result == true) { return s.substr(i, window); } if (tTmpMap.count(s[i]) > 0) { tTmpMap[s[i]]--; } } } return ""; } };

2leetcode题解一

官方题解中没有遍历窗口的大小,而是使用双指针的方式。用窗口的左边沿和右边沿来表示一个窗口,通过左右边沿的移动来遍历不同的情况。

class Solution { public: //t中字符出现的次数 unordered_map <char, int> ori; //s中字符出现的次数 unordered_map <char, int> cnt; //判断当前子串是不是覆盖了t bool check() { for (const auto &p: ori) { if (cnt[p.first] < p.second) { return false; } } return true; } string minWindow(string s, string t) { //t中字符出现的次数 for (const auto &c: t) { ori[c]++; } int l = 0;//窗口左边沿 int r = 0;//窗口右边沿 int len = INT_MAX; int ansL = -1; int ansR = -1; while (r < int(s.size())) { //统计s中字符的数量,移动窗口右边沿 if (ori.find(s[r]) != ori.end()) { cnt[s[r]]++; } //移动窗口左边沿,找到慢去条件的最小窗口 while (check() && l <= r) { if (r - l + 1 < len) { len = r - l + 1; ansL = l; } if (ori.find(s[l]) != ori.end()) { cnt[s[l]]--; } l++; } r++; } return ansL == -1 ? string() : s.substr(ansL, len); } };

3leetcode题解二

题解二比题解一性能更高。

相同点:

①都维护了两个map,分别用于记录s和t中字符出现的次数。

②窗口右边沿的移动均是沿着s进行移动,没有其它的条件约束。


不同点:

①题解二中多了一个count,用count和t的长度是否相等来表示当前子串是不是覆盖了t。当s中的字符出现次数少于t中字符的出现次数时,对count进行递增。而题解一种使用函数check来判断当前子串是不是覆盖了t。

②窗口左边沿的移动方式不同:题解一种移动左边沿,加上check函数进行判断,比较好理解;题解二中移动左边界,是当当前字符出现的次数比t中出现的次数多的时候,才会像猴移动(如果字符在t中没有出现,在s中出现了,那么会移动;如果字符在s和t中都出现了,并且在s中出现的次数比t中多,那么也可以移动)。

class Solution { public: string minWindow(string s, string t) { for (char c : t) { ht[c]++; } for (int i = 0, j = 0; i < s.size(); i++) { hs[s[i]]++; if (hs[s[i]] <= ht[s[i]]) { count++; } while (hs[s[j]] > ht[s[j]]) { hs[s[j]]--; j++; } if (count == t.size()) { if (ret.empty() || i - j + 1 < ret.size()) { ret = s.substr(j, i - j + 1); } } } return ret; } private: int hs[123] = {0}; int ht[123] = {0}; int count = 0; std::string ret = ""; };
http://www.jsqmd.com/news/736844/

相关文章:

  • Notepad++正则表达式实战:如何快速筛选出同时包含两个关键词的日志行(附零基础详解)
  • DoL-Lyra整合包:5分钟快速上手的Degrees of Lewdity美化增强版
  • Instella-3B开源模型:轻量级LLM的性能突破与实践指南
  • 信奥赛CSP-J复赛集训(模拟算法专题)(20):[NOIP 2011 提高组] 铺地毯
  • B站缓存视频一键转换终极指南:m4s-converter完整使用教程
  • 碧蓝航线Alas脚本:5分钟快速上手指南,彻底解放你的双手
  • 原位修复的最优操作尺度:分子?蛋白质?细胞?还是组织?
  • 【Docker安全红皮书更新】:27版强制网络命名空间隔离、默认拒绝模式与自动微分段(仅限企业版Early Access)
  • 为什么92%的智能座舱项目在Docker 27升级后遭遇CAN总线延迟抖动?——车规级容器实时性调优白皮书首发
  • Pytorch图像去噪实战(十七):混合损失函数图像去噪实战,解决MSE导致图像发糊的问题
  • LaViT:多模态大语言模型的视觉-语言融合创新
  • 如何用WinUtil一键搞定Windows系统优化与软件管理?
  • agenix 高级技巧:密钥轮换、多用户授权和安全威胁防范
  • 基于配置化驱动的对话AI开发:从原理到Confichat实践
  • 还在为百度网盘提取码而烦恼?3秒智能解析工具如何改变你的资源获取体验?
  • 3分钟掌握OpenSpeedy:让单机游戏时间为你加速
  • Zotero GPT插件:如何用AI智能管理你的学术文献库
  • AI多智能体工作流优化与协作机制
  • 如何快速掌握Google Breakpad:大规模应用中的崩溃数据管理与分析完整指南
  • 别再只看TTFF了!用思博伦模拟器实测GNSS模块,这5个灵敏度指标才是关键
  • web3资料汇总
  • 【AI部署】dify部署
  • 【MCP 2026 AI推理引擎集成终极指南】:20年架构师亲授5大避坑法则与3步高吞吐落地实践
  • AI代码助手垂直化:构建领域特定智能体的架构与实践
  • 哔哩下载姬完整教程:5分钟学会B站视频批量下载和8K高清保存
  • Arduino Audio Tools并发处理与缓冲区管理:打造流畅音频体验的终极指南
  • 开源技能安全扫描实战:静态代码分析守护第三方代码集成
  • XUnity AutoTranslator终极指南:轻松实现Unity游戏实时多语言翻译
  • Typeshare高级用法:泛型、约束和装饰器配置终极指南
  • 信奥赛CSP-J复赛集训(模拟算法专题)(26):[YNOI2019] 排队