前言
新的一年,好好学习。
正文
问题来源
本问题来自leetcode上的76题。
问题描述
给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
如果 S 中不存这样的子串,则返回空字符串 ““。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
示例 2:
输入: S = "AA", T = "AA"
输出: "AA"
分析:
说实话我并没有想到好的解决办法,第一反应就是暴力求解,如下是我采用回溯法的解法,很遗憾的是超时了。
func minWindow(s string, t string) string {
if len(s) < len(t) {
return ""
}
m := make(map[byte]int)
c := 0
for i := 0; i < len(t); i++ {
if _, ok := m[t[i]]; !ok {
m[t[i]] = c
c++
}
}
count := make([]int, len(m))
for i := 0; i < len(s); i++ {
if index, ok := m[s[i]]; ok {
count[index]++
}
}
tcount := make([]int, len(m))
for i := 0; i < len(t); i++ {
tcount[m[t[i]]]++
}
if !isContinue(count, tcount) {
return ""
}
return dfs(m, count, tcount, s, 0, len(s)-1)
}
func isContinue(count, tcount []int) bool {
for i := 0; i < len(count); i++ {
if count[i] < tcount[i] {
return false
}
}
return true
}
func dfs(m map[byte]int, count, tcount []int, s string, start, end int) string {
if !isContinue(count, tcount) {
return ""
}
index, ok := m[s[start]]
if ok {
count[index]--
}
t1 := dfs(m, count, tcount, s, start+1, end)
if t1 == "" {
t1 = s[start:end+1]
}
if ok {
count[index]++
}
index, ok = m[s[end]]
if ok {
count[index]--
}
t2 := dfs(m, count, tcount, s, start, end-1)
if t2 == "" {
t2 = s[start:end+1]
}
if ok {
count[index]++
}
if len(t1) > len(t2) {
return t2
}
return t1
}
这道题和去年做的leetcode 3的思想是类似的,可以重新复习一下
参考网上的代码
思路:思路很简单,就是遍历数组,先把所有的T中的字符找到,然后从左端缩减这个字符串,直到不能完全包含T.但是实现起来还是需要一些技巧.因为时间复杂度限制在了O(n),所以需要在O(1)的时间内判断是不是找到了所有的T中的字符.可以用一个hash表来计数所有字符出现的次数和一个标记num代表T总共有多少字符.
然后遍历S,并且将当前字符在hash表中计数减一,如果当前字符在hash表中计数是大于0的,说明这个字符是出现在T中的,将num也减一,代表我们找到了一个(这个num就是总共有多少字符,我们需要这个来标记是不是找完了所有字符,这也是能够在O(1)时间内判断当前窗口是不是覆盖了T的关键).这样当总的数量为0的时候我们就找到了一个覆盖T的子串窗口.这个窗口因为左端可能包含了一些不必要的字符,因此我们需要将窗口的左端向右移动,使其正好包含T.在窗口左端向右移动的过程中需要将碰到字符在hash表中+1,如果当前字符在hash表中的计数为0,而且我们又碰到了,说明这个字符是出现在T中的,因此num要加一.
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> hash;
int num = t.size(), len=INT_MAX, start =0, left = 0;
for(auto val: t) hash[val]++;
for(int i =0; i < s.size(); i++)
{
if(hash[s[i]]-- >0) num--;
while(num ==0)
{
len = (i-left+1)<len?(i-(start=left)+1):len;
if(hash[s[left++]]++ ==0) num++;
}
}
return len==INT_MAX?"":s.substr(start, len);
}
};
然后给出自己golang的实现版本
func minWindow(s string, t string) string {
if len(s) < len(t) {
return ""
}
m := make(map[byte]int)
cnt := len(t)
min := math.MaxInt32
start, left := 0, 0
for i := 0; i < cnt; i++ {
m[t[i]]++
}
for i :=0; i < len(s); i++ {
if m[s[i]] > 0 {
cnt--
}
m[s[i]]--
for cnt == 0 {
if min > i - left + 1 {
min = i - left + 1
start = left
}
if m[s[left]] == 0 {
cnt++
}
m[s[left]]++
left++
}
}
if min == math.MaxInt32 {
return ""
}
return s[start:start+min]
}
要注意的是golang不能像c++一样采用 if m[s[i]]– > 0 这样的写法,必须将这样的写法进行分解。拆解为 if m[s[i]] > 0 和 m[s[i]]–;golang没有前置++操作;golang没有 (judgement) ? (statement) : (statement) 的三目运算
总结:
勤思考。
结语
不管怎么样好好加油。