剑指offer 专项突破版 17、含有所有字符的最短字符串

题目链接

哈希表+双指针

思路一
  • 首先用一个哈希表记录t中所有的字符,出现后对应位置数量–(可以用数组模拟,如果说是字母需要开的大小是58,如果说是小写字母or大写字母,要开的大小是26)
  • 然后双指针遍历s,需要注意三点
    • 一个数组即可

    • 判断现在是否包含s应该判断int数组是否每一位都>=0

    • 在移动了left后要进行标记,方便后续更新子数组间距

      while (isContains(charNums)) {
          charNums[s.charAt(left++) - 'A']--;
          flag = true;
      }
      if (flag) {
          if (right - left < end - begin) {
              begin = left - 1;
              end = right;
          }
      
    • PS:也可以把更新放到while循环中

      class Solution {
      
          boolean isContains(int[] nums) {
              for (int num : nums) {
                  if (0 > num)
                      return false;
              }
              return true;
          }
      
          public String minWindow(String s, String t) {
              int[] charNums = new int[60];
              int begin = 0, end = Integer.MAX_VALUE, left = 0, right = t.length();
              boolean flag = false;
      
              if(t.length() > s.length())
                  return "";
      
              for (int i = 0; i < t.length(); i++) {
                  charNums[t.charAt(i) - 'A']--;
                  charNums[s.charAt(i) - 'A']++;
              }
              if (isContains(charNums))
                  end = t.length();
      
              while (right < s.length()) {
                  charNums[s.charAt(right++) - 'A']++;
                  while (isContains(charNums)) {
                      charNums[s.charAt(left++) - 'A']--;
                      flag = true;
                  }
                  if (flag) {
                      if (right - left < end - begin) {
                          begin = left - 1;
                          end = right;
                      }
                      flag = false;
                  }
              }
              return end == Integer.MAX_VALUE ? "" : s.substring(begin, end);
          }
      }
      
思路二
  • 直接使用哈希表,同样是对于t中出现的字符,直接记录到表中(出现一次,次数-1)
  • 为了避免每一次在判断是否是子字符串时都要遍历哈希表的全部,我们维护了一个count变量,注意代码中对count变量的操作(这个方法中我们把更新left和更新子字符串的长度放到了一起)
    class Solution {
    
        public String minWindow(String s, String t) {
            int left = 0, right = 0, minLeft = 0, minRight = Integer.MAX_VALUE, count = 0;
            HashMap<Character, Integer> charToCount = new HashMap<>();
    
            if (minRight < right)
                return "";
    
            for (Character ch : t.toCharArray()) {
                int time = charToCount.getOrDefault(ch, 0);
                if (0 == time)
                    count++;
                charToCount.put(ch, time - 1);
            }
    
            while (right < s.length() &&  left <= right || 0 == count) {
                //此时并未包含所有 t 中的字符
                if (0 != count) {
                    char ch = s.charAt(right++);
                    //如果字符 ch 是t中的某一个字符
                    if (charToCount.containsKey(ch)) {
                        int time = charToCount.get(ch) + 1;
                        charToCount.put(ch, time);
                        if (0 == time)
                            count--;
                    }
                } else {
                    if (right - left < minRight - minLeft) {
                        minRight = right;
                        minLeft = left;
                    }
                    char ch = s.charAt(left++);
                    if (charToCount.containsKey(ch)) {
                        int time = charToCount.get(ch) - 1;
                        charToCount.put(ch, time);
                        if (-1 == time)
                            count++;
                    }
                }
            }
            return minRight == Integer.MAX_VALUE ? "" : s.substring(minLeft, minRight);
        }
    }
    
Go版本
func minWindow(s string, t string) string {
	if len(t) > len(s) {
		return ""
	}
	m := make(map[rune]int)
	for _, ch := range t {
		m[ch]--
	}

	left, result := 0, s+" "
	for i := 0; i < len(s); i++ {
		m[rune(s[i])]++
		for contains(m) {
			result = min(result, s[left:i+1])
			m[rune(s[left])]--
			left++
		}
	}
	if len(result) > len(s){
		return ""
	}
	return result
}

func contains(m map[rune]int) bool {
	for _, v := range m {
		if v < 0 {
			return false
		}
	}
	return true
}

func min(s, t string) string {
	if len(s) < len(t) {
		return s
	}
	return t
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值