算法leetcode|76. 最小覆盖子串(rust重拳出击)

news2024/12/23 18:50:37

文章目录

  • 76. 最小覆盖子串:
    • 样例 1:
    • 样例 2:
    • 样例 3:
    • 提示:
    • 进阶:
  • 分析:
    • 在这里插入图片描述
  • 题解:
    • rust:
    • go:
    • c++:
    • python:
    • java:


76. 最小覆盖子串:

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""

注意

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

样例 1:

输入:
	
	s = "ADOBECODEBANC", t = "ABC"
	
输出:
	
	"BANC"
	
解释:
	
	最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

样例 2:

输入:
	
	s = "a", t = "a"
	
输出:
	
	"a"
	
解释:
	
	整个字符串 s 是最小覆盖子串。

样例 3:

输入: 
	
	s = "a", t = "aa"
	
输出: 
	
	""
	
解释:

	 t 中两个字符 'a' 均应包含在 s 的子串中,
	因此没有符合条件的子字符串,返回空字符串。

提示:

  • m == s.length
  • n == t.length
  • 1 <= m, n <= 105
  • st 由英文字母组成

进阶:

你能设计一个在 o(m + n) 时间内解决此问题的算法吗?


分析:

  • 面对这道算法题目,二当家的再次陷入了沉思。
  • 直接采用双层循环暴力解决的话,时间复杂度会比较高,恐怕过不了用例,没有去试。
  • 题目并不要求字符的顺序,只要求了每种字符的数量,那首先就想到要做计数。
  • 接下来考虑如何降低时间复杂度,每次循环都从新匹配子串是低效的,要尽可能复用,滑动窗口在这里非常合适,使用双指针,先直接移动右指针找到第一个满足条件的子串,记下长度作为备选结果,接下来移动左指针,当不满足覆盖子串的条件时就继续移动右置针直到满足覆盖子串d饿条件,并比较子串的长度,取较小的子串长度作为备选结果,重复该操作,直到循环遍历完毕。
  • 如何高效判断遍历的子串已经满足覆盖子串呢?字符计数这时候就要大展拳脚了,先在遍历字符串 s 之前,先对字符串 t 进行一次遍历,做初始化计数,记录下每种字符的个数(题解中这里使用了减法,使用加法也是可以的,只是后面的加减法就要变),在遍历 s 时,移动右指针就是延长了覆盖子串,同时修改计数,这里的加减法计算要和前面初始化的相反,判断计数是否为0,如果变为0则表示,这种字符的个数已经没有差异了,但是我们需要覆盖了 t 中的每一种字符,所以需要判断 26 个字符的个数是不是都够了,如果都够了,就是满足了覆盖子串,接下来就移动左指针,同时修改计数,这里的加减计算要和右指针移动的相反。
  • 当某个字符的计数变为0时,我们需要判断 26 种字符的字符个数是不是都满足了,这里就需要26次循环,是否有更高效的办法呢?我们可以额外增加一个变量记录有差异的字符种类数(记录有差异的字符数也是可以的,但是后面的逻辑会有一点区别,思想大致相同), 初始化时顺便初始化该变量,在遍历匹配中,每当有字符计数变为0,就修改这个变量,如果这个变量变为0则表示完全覆盖,从而提高效率。
  • 只看文字可能不便理解,建议对照着熟悉的语言的题解一起看,希望可以有助学习理解。

在这里插入图片描述

题解:

rust:

impl Solution {
    pub fn min_window(s: String, t: String) -> String {
        // 少于目标字符串中数量的字符数量
        let mut diff_char_count = 0;
        // 字符计数器
        let mut cnt = vec![0; 128];

        // 初始化
        t.as_bytes().iter().for_each(|&b| {
            // 计数减少
            cnt[b as usize] -= 1;
            if cnt[b as usize] == -1 {
                // 差异字符数增加
                diff_char_count += 1;
            }
        });

        // 覆盖子串结果信息
        let (mut ans_len, mut ans_l) = (usize::MAX, usize::MAX);

        // 开始滑动窗口
        let s_len = s.len();
        let (mut l, mut r) = (0, 0);
        while r < s_len {
            // 计数增加
            cnt[s.as_bytes()[r] as usize] += 1;

            // 向右移动右边界后,可能该字符数量没有差异了
            if cnt[s.as_bytes()[r] as usize] == 0 {
                // 差异字符数减少
                diff_char_count -= 1;
                // 差异字符数减少后可能为0了
                if diff_char_count == 0 {
                    // 向右滑动左边界,直到会有差异,取满足要求的最小串
                    while cnt[s.as_bytes()[l] as usize] > 0 {
                        cnt[s.as_bytes()[l] as usize] -= 1;
                        l += 1;
                    }

                    // 更新结果
                    if r - l + 1 < ans_len {
                        ans_len = r - l + 1;
                        ans_l = l;
                    }

                    // 向右移动左边界,差异字符数增加
                    cnt[s.as_bytes()[l] as usize] -= 1;
                    l += 1;
                    diff_char_count += 1;
                }
            }
            r += 1;
        }

        return if ans_l == usize::MAX {
            "".to_string()
        } else {
            s[ans_l..ans_l + ans_len].to_string()
        }
    }
}

go:

func minWindow(s string, t string) string {
    // 少于目标字符串中数量的字符数量
	diffCharCount := 0
	// 字符计数器
	cnt := make([]int, 128)

	// 初始化
	for _, c := range t {
		// 计数减少
		cnt[c]--
		if cnt[c] == -1 {
			// 差异字符数增加
			diffCharCount++
		}
	}

	// 覆盖子串结果信息
	ansLen, ansL := math.MaxInt32, -1

	// 开始滑动窗口
	sLen := len(s)
	l, r := 0, 0
	for r < sLen {
		// 计数增加
		cnt[s[r]]++

		// 向右移动右边界后,可能该字符数量没有差异了
		if cnt[s[r]] == 0 {
			// 差异字符数减少
			diffCharCount--
			// 差异字符数减少后可能为0了
			if diffCharCount == 0 {
				// 向右滑动左边界,直到会有差异,取满足要求的最小串
				for cnt[s[l]] > 0 {
					cnt[s[l]]--
					l++
				}

				// 更新结果
				if r-l+1 < ansLen {
					ansLen = r - l + 1
					ansL = l
				}

				// 向右移动左边界,差异字符数增加
				cnt[s[l]]--
				l++
				diffCharCount++
			}
		}
		r++
	}

	if ansL == -1 {
		return ""
	} else {
		return s[ansL : ansL+ansLen]
	}
}

c++:

class Solution {
public:
    string minWindow(string s, string t) {
        // 少于目标字符串中数量的字符数量
        int diffCharCount = 0;
        // 字符计数器
        int cnt[128];
        memset(cnt, 0, sizeof(cnt));

        // 初始化
        const int tLen = t.length();
        for (int i = 0; i < tLen; ++i) {
            if (--cnt[t[i]] == -1) {
                // 差异字符数增加
                ++diffCharCount;
            }
        }

        // 覆盖子串结果信息
        int ansLen = INT_MAX, ansL = -1;

        // 开始滑动窗口
        const int sLen = s.length();
        int l = 0, r = -1;
        while (++r < sLen) {
            // 向右移动右边界后,可能该字符数量没有差异了
            if (++cnt[s[r]] == 0) {
                // 差异字符数减少后可能为0了
                if (--diffCharCount == 0) {
                    // 向右滑动左边界,直到会有差异,取满足要求的最小串
                    while (--cnt[s[l++]] >= 0) {
                        // nothing
                    }

                    // 差异字符数增加
                    ++diffCharCount;

                    // 更新结果
                    if (r - l + 2 < ansLen) {
                        ansLen = r - l + 2;
                        ansL = l - 1;
                    }
                }
            }
        }

        return ansL == -1 ? "" : s.substr(ansL, ansLen);
    }
};

python:

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        # 少于目标字符串中数量的字符数量
        diff_char_count = 0
        # 字符计数器
        cnt = collections.defaultdict(int)

        # 初始化
        for c in t:
            # 计数减少
            cnt[c] -= 1
            if cnt[c] == -1:
                # 差异字符数增加
                diff_char_count += 1

        # 覆盖子串结果信息
        ans_len, ans_l = float("inf"), -1

        # 开始滑动窗口
        s_len = len(s)
        l, r = 0, 0
        while r < s_len:
            # 计数增加
            cnt[s[r]] += 1

            # 向右移动右边界后,可能该字符数量没有差异了
            if cnt[s[r]] == 0:
                # 差异字符数减少
                diff_char_count -= 1
                # 差异字符数减少后可能为0了
                if diff_char_count == 0:
                    # 向右滑动左边界,直到会有差异,取满足要求的最小串
                    while cnt[s[l]] > 0:
                        cnt[s[l]] -= 1
                        l += 1

                    # 更新结果
                    if r - l + 1 < ans_len:
                        ans_len = r - l + 1
                        ans_l = l

                    # 向右移动左边界,差异字符数增加
                    cnt[s[l]] -= 1
                    l += 1
                    diff_char_count += 1
            r += 1

        return "" if ans_l == -1 else s[ans_l: ans_l + ans_len]


java:

class Solution {
    public String minWindow(String s, String t) {
        // 少于目标字符串中数量的字符数量
        int diffCharCount = 0;
        // 字符计数器
        final int[] cnt = new int[128];

        // 初始化
        final int tLen = t.length();
        for (int i = 0; i < tLen; ++i) {
            if (--cnt[t.charAt(i)] == -1) {
                // 差异字符数增加
                ++diffCharCount;
            }
        }

        // 覆盖子串结果信息
        int ansLen = Integer.MAX_VALUE, ansL = -1;

        // 开始滑动窗口
        final int sLen = s.length();
        int       l    = 0, r = -1;
        while (++r < sLen) {
            // 向右移动右边界后,可能该字符数量没有差异了
            if (++cnt[s.charAt(r)] == 0) {
                // 差异字符数减少后可能为0了
                if (--diffCharCount == 0) {
                    // 向右滑动左边界,直到会有差异,取满足要求的最小串
                    while (--cnt[s.charAt(l++)] >= 0) {
                        // nothing
                    }

                    // 差异字符数增加
                    ++diffCharCount;

                    // 更新结果
                    if (r - l + 2 < ansLen) {
                        ansLen = r - l + 2;
                        ansL = l - 1;
                    }
                }
            }
        }

        return ansL == -1 ? "" : s.substring(ansL, ansL + ansLen);
    }
}

非常感谢你阅读本文~
欢迎【点赞】【收藏】【评论】三连走一波~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://le-yi.blog.csdn.net/ 博客原创~


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/970870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态贴纸、美颜SDK与AR:创造独特的互动体验

目前&#xff0c;动态贴纸、美颜SDK、增强现实&#xff08;AR&#xff09;等技术是比较热门的话题&#xff0c;它们所结合的新兴玩法更是收到大家推崇&#xff0c;正潜移默化的改变我们与数字世界互动的方式。 一、动态贴纸&#xff1a;个性化互动的开始 动态贴纸&#xff0c…

智能聊天机器人,帮你排解烦恼!

在繁忙的生活中&#xff0c;你是否曾经感到压力和烦恼无处宣泄&#xff1f;现在&#xff0c;我们为你带来了一款全新的智能聊天机器人&#xff0c;它能够倾听你的心声&#xff0c;理解你的情绪&#xff0c;为你提供安慰和支持&#xff0c;让你告别烦恼&#xff0c;重拾快乐生活…

ToBeWritten之基于ATTCK的运营流程与实践

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

Mysql底层数据结构为什么选择B+树

索引底层采用什么数据结构&#xff0c;为什么使用B树而不是其他数据结构&#xff1a; &#xff08;1&#xff09;如果采用二叉树&#xff1a;使用递增字段作为索引时&#xff0c;二叉树会退化成链表&#xff0c;查找效率太低 &#xff08;2&#xff09;如果采用红黑树&#xf…

2023年新风口,Kwai快手海外公会入驻详细指南!

Kwai快手海外公会发展前景作为中国短视频市场的领头羊&#xff0c;Kwai快手在海外市场也取得了一定的成绩。但是&#xff0c;海外市场的发展前景还存在一些不确定因素&#xff0c;需要快手进一步探索和努力。首先&#xff0c;海外市场对于内容的申请找cmxyci要求与国内市场有所…

系统学习Linux-zabbix监控平台

一、zabbix的基本概述 zabbix是一个监控软件&#xff0c;其可以监控各种网络参数&#xff0c;保证企业服务架构安全运营&#xff0c;同时支持灵活的告警机制&#xff0c;可以使得运维人员快速定位故障、解决问题。zabbix支持分布式功能&#xff0c;支持复杂架构下的监控解决方…

ZLMeidaKit在Windows上启动时:计算机中丢失MSVCR110.dll,以及rtmp推流后无法转换为flv视频流解决

场景 ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放&#xff1a; ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放_zlm流媒体服务器_霸道流氓气质的博客-CSDN博客 按照以上教程启动MediaServer.exe时提示&am…

新上线:爱校对的PDF校对工具,专为专业人士设计

在这个信息爆炸的时代&#xff0c;准确和专业的信息交流比以往任何时候都更为重要。专业人士&#xff0c;无论是律师、医生、研究人员还是企业高管&#xff0c;都依赖于高质量的PDF文档来进行准确无误的沟通。但是&#xff0c;校对这些文档常常是一个既耗时又容易出错的任务。这…

智汇云舟携三大自研产品体系亮相服贸会

9月2日&#xff0c;2023年中国国际服务贸易交易会在北京开幕。在电信、计算机和信息服务专题展馆中&#xff0c;北京智汇云舟科技有限公司&#xff08;以下简称智汇云舟&#xff09;携视频孪生场景化一体机、视频孪生能力平台、视频孪生行业解决方案三大自研产品体系亮相服贸会…

android studio 的 adb配置

首先在 Android Studio 中 打开 File -> Settings: 下载 “Google USB Driver” 这个插件 (真机调试的时候要用到), 并且记一下上面的SDK路径: 右键桌面上的 “我的电脑”, 点击 “高级系统设置”, 配置计算机的高级属性, 有两步: 添加一个新的环境变量 ANDROID_HOME, 变量…

【教学类-36-06】20230707动物面具-正方形(midjounery-niji)(涂色、裁剪、镂空剪、实用性研究(怎样贴在脸上))

作品展示 1、使用15:15CM彩色手工纸打印&#xff08;25*25的纸超过21CM的边&#xff0c;打印机放不下&#xff09;&#xff0c; 2、打开选择CAJ阅读器 3、纸张放在纸屉内&#xff0c;用三个架子缩小页面 4、哎&#xff0c;大不了&#xff0c;换不了纸 一、利用midjounery获…

比特币再起风波!

今日荐读&#xff1a;9.2教链内参《马斯克收购推特背后鲜为人知的故事》。刘教链Pro《激辩&#xff1a;比特币究竟算不算财产&#xff1f;》。 * * * 刘教链 原创 * * * 经历过2017-2018年BCH硬分叉战争的人应当还对当年的血雨腥风心有余悸。当然&#xff0c;对于一战之后进场…

C#学习系列之UDP同端口收发问题

C#学习系列之UDP同端口收发问题 前言解决办法关于JoinMulticastGroup总结 前言 想测试自己的程序问题&#xff0c;建立了两个UDP程序&#xff0c;一个往端口中接到数就传出去&#xff0c;另一个从这个端口接数据来解析。 出现的问题是 每次打开端口&#xff0c;另一个程序就无…

Applovin股价飞涨,同场竞技的汇量或将拿到相同剧本

全球化、跨行业投资是对冲投资风险、实现超额收益的重要方式。若论什么行业在全球化投资中入门最简单&#xff0c;那一定是互联网。APP、游戏人人都能接触&#xff0c;轻松解决了对商业门槛的理解问题&#xff0c;所有的增长价值一清二楚。 但互联网作为一个看起来非常成熟的行…

领跑车载5G/V2X模组市场,移远通信又获大奖

汽车行业的智能化、网联化发展&#xff0c;离不开车载模组的支撑&#xff0c;作为车联网的重要组成部分&#xff0c;5G、V2X等技术的发展和应用对智能网联汽车的不断升级有着重要的推动意义&#xff0c;受到了业界的广泛关注。 8月31日&#xff0c;在2023高工智能汽车行业评选颁…

【ProxMox7.2】创建win10虚拟机

创建win10虚拟机 1.创建虚拟机2.操作系统3.系统4.磁盘5.CPU设置6.内存7. 网络8.确认9. 安装 1.创建虚拟机 名字随便命名 2.操作系统 这里选择自己ios版本选择 2008r2类型 选择windows 3.系统 机型选择默认i44fxscsi控制器选择Virtio Scsi 4.磁盘 这里存储选择自己大的一…

【Day-28慢就是快】代码随想录-二叉树-平衡二叉树

给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a;一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 思路 求深度可以从上到下去查 所以需要前序遍历&#xff08;中左右&#xff09; 而高度只能…

pmp和软件高项哪个含金量高?

人们常将PMP和高项放在一起比较&#xff0c;因为这两种证书都适用于项目经理职位&#xff0c;它们有高达60%的知识点重合度。在决定考哪一种证书之前&#xff0c;人们常常会感到困惑。 下面看一下pmp和软考高项的差异。 发证机构不同 PMP(Project Management Professional)是…

【VL tracking】Towards Unified Token Learning for Vision-Language Tracking

不知道什么原因学校认证账号进不去&#xff0c;下载不了最新的PDF 广西师范大学 | 国科大 | 厦大 代码开源 zhihu指路&#x1f449;【VL tracking】MMTrack阅读 问题 一方面&#xff0c;传统的VL tracking方法需要昂贵的先验知识。例如&#xff0c;一些tracker是专门用于bou…

单片机简介

目录 1、单片机 2、CISC和RISC 3、 冯诺依曼结构和哈佛结构​编辑 1、单片机 单片机:Single-Chip Microcomputer,单片微型计算机,是一种集成电路芯片 ------------------------------------------------------------ 电脑&#xff1a; <--------> …