leedcode 76.最小覆盖字串(哈希表,滑动窗口)

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

注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
 
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:

输入:s = "a", t = "a"
输出:"a"
示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
 

提示:

1 <= s.length, t.length <= 105
s 和 t 由英文字母组成
 

思路:相当于在str2字符串中找一个包含str1的字符子串并输出(只要包含就行,不考虑顺序) 

用o(n)的时间来解决这道题,因此我们考虑用哈希数组来记录str1字符串中每个字符出现的次数,只要str2中的一个子字符串中的字符和有str1中的字符且出现次数一样  就将找个子字符串输出来

难点:怎么缩小区间

当hash_str2[str2[j]] > hash_str1[str2[j]],我们说某个数的字符出现次数太多了 我们可以将其删去,缩小区间

#include<iostream>
#include<unordered_map>
#include<string>
using namespace std;
int main() {
	int cnt=0;
	int minstr = 0x3f3f3f3f;
	unordered_map<char, int>hash_str1; 
	unordered_map<char, int>hash_str2;
	string  str1;
	string str2;
	string ans;
	cin >> str2;//大的字符串
	cin >> str1;//小的字符串
	
	for (int i = 0; i < str1.size(); i++) {
		hash_str1[str1[i]]++;//将字串中的字符出现的次数统计在哈希数组中
	}
	for (int i = 0, j = 0; i < str2.size(); i++) {
        if (hash_str2[str2[i]] < hash_str1[str2[i]]) {
			cnt++;
		}
		hash_str2[str2[i]]++;
		//怎样实现统计str2中的str1 ,如果够了则不在移动i,移动j。
		
		while (hash_str2[str2[j]] > hash_str1[str2[j]]) {//让左指针j向右移直到右移到是最小的覆盖字串为止
			
			hash_str2[str2[j]]--;
			j++;
		}
		if (cnt == str1.size()) {
			if ( i - j + 1 < minstr) {//筛选最小字串
				minstr = i - j + 1;
				ans = str2.substr(j, i - j + 1);
				cout << "ans:" << ans << endl;
			}
		}
	}
	return 0;
}

 

<think>好的,我需要帮助用户了解如何使用哈希表进行字符串查找。首先,哈希表是什么?哈希表是一种数据结构,可以通过键值对快速存储和检索数据。在字符串查找中,哈希表可以用来快速判断某个字符或子字符串是否存在,或者统计字符出现的次数。 根据用户提供的引用,特别是引用[4],里面提到了字符哈希的例子,使用一个数组来统计字符出现的次数。这可能是一个简单而有效的方法。比如,可以用字符的ASCII码作为数组的索引,数组的值表示该字符出现的次数。这样,查找某个字符是否存在只需要O(1)的时间。 另外,引用[2]提到使用HashSet作为滑动窗口来检查字符是否存在于当前子字符串中。这可能用于解决如最长无重复子字符串的问题,但用户的问题是字符串查找,所以可能更关注如何快速判断某个字符或子串是否存在。 接下来,我需要整理出几种常见的使用哈希表进行字符串查找的方法,并给出示例代码。可能的方法包括: 1. 字符统计:统计每个字符出现的次数,用于快速查找字符是否存在或出现的次数。 2.字符串匹配:使用哈希表存储子字符串的哈希值,以快速比较。 3. 字符串去重:使用哈希表存储已出现的字符,以判断重复。 4. 模式匹配:如引用[3]提到的,双向映射检查字符串是否符合某种模式,例如LeetCode的单词模式题。 需要结合用户提供的引用内容,特别是引用[4]中的示例代码,展示如何用数组实现字符统计。同时,引用[1]提到哈希映射优化字符串操作,可以说明哈希表在提高效率方面的优势。 可能的结构如下: - 方法一:字符统计(使用数组模拟哈希表) - 示例代码,如统计字符出现次数 - 应用场景:查找字符是否存在,统计频率等 - 方法二:子字符串快速查找(如Rabin-Karp算法中的哈希应用) - 示例代码可能较复杂,但可以简要说明原理 - 方法三:字符串去重或重复检查 - 使用HashSet存储已出现的字符,判断是否重复 - 方法四:模式匹配(双向映射) - 如LeetCode的单词模式问题,使用两个哈希表确保一一对应 每个方法需要给出具体示例和代码,同时结合用户提供的引用内容,确保引用正确。例如,在方法一中引用[4],在方法二中引用[2]或[1]。 需要注意的是,用户的问题可能更偏向于基础的字符串查找,比如查找特定字符是否存在,或者统计字符出现次数,因此可能需要重点讲解方法一和方法三,而方法二和方法四可以作为扩展应用。 现在,我需要确保每个方法都有对应的引用支持,并且代码示例正确。例如,字符统计的代码可以直接从引用[4]中提取,但可能需要用Python改写,因为用户提供的示例代码是Python的。或者保持原样,说明是C++代码,但用户可能更希望看到Python示例? 用户之前的示例中有Python代码,但引用中的示例是C++。可能需要根据用户的需求,提供Python的示例代码,或者说明不同语言中的实现方式。不过用户的问题并没有指定语言,所以可能需要用通用的说明,或者同时提供不同语言的例子? 可能更好的做法是使用Python示例,因为用户给出的快速排序示例是Python的。但引用[4]中的代码是C++,需要指出这一点,但提供Python的实现。 例如,在方法一中,可以展示C++的代码(如引用中的),然后给出Python的实现,或者仅用Python。不过用户的问题可能希望看到具体的方法,而语言不是关键,所以可能用Python更合适。 综上,整理出几个方法,每个方法结合引用,给出示例代码,并说明应用场景。最后生成相关问题。</think>### 使用哈希表实现字符串查找的方法及示例 哈希表通过键值对的映射关系,能够以 $O(1)$ 的平均时间复杂度快速判断元素是否存在。在字符串操作中,哈希表常用于字符统计、子字符串查找、去重和模式匹配等场景。以下是具体方法及示例: --- #### 方法一:字符统计(数组模拟哈希表) **原理** 利用字符的 ASCII 码值作为数组下标,统计每个字符出现的次数。适用于快速查找字符是否存在或统计频率。 **示例代码(C++)** 引用[4]中的示例: ```cpp #include<stdio.h> #include<string> #include<stdlib.h> using namespace std; int main() { int char_map[128] = {0}; // 初始化数组 string str = "snaxjnjsxngdpq"; for (int i=0; i<str.length(); i++) { char_map[str[i]]++; // 统计字符出现次数 } for (int i=0; i<128; i++) { if (char_map[i] > 0) printf("[%c][%d]: %d\n", i, i, char_map[i]); // 输出结果 } return 0; } ``` **Python 实现** ```python def count_chars(s): char_map = [0] * 128 # ASCII 范围 0-127 for c in s: char_map[ord(c)] += 1 for i in range(128): if char_map[i] > 0: print(f"字符 {chr(i)} 出现次数: {char_map[i]}") count_chars("snaxjnjsxngdpq") ``` **应用场景** - 统计字符串中重复字符。 - 判断字符串是否由唯一字符组成(所有值 $\leq 1$)[^4]。 --- #### 方法二:子字符串快速查找(哈希映射优化) **原理** 利用哈希表存储子字符串的哈希值,减少重复计算。例如 **Rabin-Karp 算法**通过滚动哈希快速匹配子字符串。 **示例代码(Python)** 查找字符串中是否包含目标子串: ```python def contains_substring(s, target): target_hash = hash(target) n = len(target) for i in range(len(s) - n + 1): if hash(s[i:i+n]) == target_hash: # 实际需处理哈希冲突 return True return False ``` **优化说明** 实际应用中需使用滚动哈希(如多项式哈希)避免重复计算,时间复杂度可降至 $O(n+m)$[^1]。 --- #### 方法三:字符串去重(HashSet) **原理** 利用哈希集合存储已出现的字符,快速判断是否重复。 **示例代码(Python)** ```python def has_duplicate(s): seen = set() for c in s: if c in seen: # O(1) 时间判断 return True seen.add(c) return False ``` **应用场景** - 判断字符串是否有重复字符。 - 滑动窗口算法中维护无重复子串[^2]。 --- #### 方法四:模式匹配(双向哈希映射) **原理** 使用两个哈希表分别记录字符与单词的映射关系,确保双向唯一性(如 LeetCode 的「单词模式」问题)。 **示例代码(Python)** ```python def word_pattern(pattern, s): words = s.split() if len(pattern) != len(words): return False char_to_word = {} word_to_char = {} for c, word in zip(pattern, words): if c in char_to_word: if char_to_word[c] != word: return False else: if word in word_to_char: return False char_to_word[c] = word word_to_char[word] = c return True ``` **应用场景** - 检测字符串是否符合特定模式(如 `abba` 对应 `dog cat cat dog`)[^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值