leetcode热题100-GO解-2025.3.21 12/100
今日主要在调整butterfly主题配色等,简单堆堆数量了今天
堆数量失败,两道困难题
560.和为K的子数组 给你一个整数数组 nums
和一个整数 k
,请你统计并返回 该数组中和为 k
的子数组的个数 。
子数组是数组中元素的连续非空序列。
示例 1:
1 2 输入:nums = [1,1,1], k = 2 输出:2
示例 2:
1 2 输入:nums = [1,2,3], k = 3 输出:2
提示:
1 <= nums.length <= 2 * 104
-1000 <= nums[i] <= 1000
-107 <= k <= 107
采用前缀和加哈希表标准解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 func subarraySum (nums []int , k int ) int { m := make (map [int ]int ) m[0 ] = 1 count := 0 pre := 0 for i := 0 ; i < len (nums); i++ { pre += nums[i] if _, ok := m[pre-k]; ok { count += m[pre-k] } m[pre] += 1 } return count }
239.滑动窗口最大值 给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 和 --------------- ----- [1 3 -1] -3 5 3 6 7 3 3 1 [3 -1 -3] 5 3 6 7 3 -1 1 3 [-1 -3 5] 3 6 7 5 1 1 3 -1 [-3 5 3] 6 7 5 5 1 3 -1 -3 [5 3 6] 7 6 14 1 3 -1 -3 5 [3 6 7] 7 16 [7 2] 4 7 9 7 [2 4] 6 6
示例 2:
1 2 输入:nums = [1], k = 1 输出:[1]
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
预计采用邪道解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func maxSlidingWindow (nums []int , k int ) []int { if k == 1 { return nums } else if k == len (nums) { return []int {Max(nums)} } res := make ([]int , 0 ) l := len (nums) currentMax := Max(nums[:k]) res = append (res, currentMax) for i, v := range nums[:l-k] { if v == currentMax { currentMax = Max(nums[i+1 : i+k+1 ]) } else if nums[i+k] > currentMax { currentMax = nums[i+k] } res = append (res, currentMax) } return res }
采用正常解法
采用单调栈,这种解法之前确实没专门看过,不知道具体如何维护,上述解法实际上约等于记录max和2ndMax来进行迭代,过于粗糙了
依此代码逻辑,队列为降序存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 func maxSlidingWindow (nums []int , k int ) []int { if k == 1 { return nums } else if k == len (nums) { return []int {Max(nums)} } n := len (nums) result := make ([]int , n-k+1 ) var queue []int for i := 0 ; i < n; i++ { for len (queue) > 0 && queue[0 ] <= i-k { queue = queue[1 :] } for len (queue) > 0 && nums[queue[len (queue)-1 ]] < nums[i] { queue = queue[:len (queue)-1 ] } queue = append (queue, i) if i >= k-1 { result[i-k+1 ] = nums[queue[0 ]] } } return result }
76.最小覆盖子串 给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
对于 t
中重复字符,我们寻找的子字符串中该字符数量必须不少于 t
中该字符数量。
如果 s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
1 2 3 输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
示例 2:
1 2 3 输入:s = "a", t = "a" 输出:"a" 解释:整个字符串 s 是最小覆盖子串。
示例 3:
1 2 3 4 输入: s = "a", t = "aa" 输出: "" 解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。
还是滑动窗口
使用target map[byte]int
来统计结果中需要的字母及数量
使用valid int
与len(target)
作比较判断右指针是否已经移动到了能包含子串的位置
使用window map(byte)int
来统计窗口内字母及数量
在valid == len(target)
条件达成后
先判断当前左右差是否能更新最短长度,若可以,更新指向子串起始的start指针及长度
暂存要移出的最左字符(因为其是两个统计map的key),再移动左指针
先判断移出的是否是所需字母,不是则直接进入下一次循环
移出的是所需字母,再判断window[d]
与target[d]
是否相等,不相等则破坏条件,window[d]--
,同时valid--
导致不满足valid == len(target)
,跳出循环
回到移动右指针过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 func minWindow (s string , t string ) string { if len (s) < len (t) { return "" } if len (s) == len (t) && len (t) == 1 { return func () string { if s == t { return s } return "" }() } target := make (map [byte ]int ) for i := 0 ; i < len (t); i++ { target[t[i]]++ } window := make (map [byte ]int ) valid := 0 start, minLen := 0 , len (s)+1 left, right := 0 , 0 for right < len (s) { c := s[right] right++ if _, ok := target[c]; ok { window[c]++ if window[c] == target[c] { valid++ } } for valid == len (target) { if right-left < minLen { start = left minLen = right - left } d := s[left] left++ if _, ok := target[d]; ok { if window[d] == target[d] { valid-- } window[d]-- } } } if minLen == len (s)+1 { return "" } return s[start : start+minLen] }
虽然只写了两题,但两题困难难度,也当自己任务完成吧。