我是靠谱客的博主 饱满薯片,这篇文章主要介绍【Leetcode】992. Subarrays with K Different Integers解法,现在分享给大家,希望可以做个参考。

1

解法

解法一:LRU Cache

考虑以A[j]为结尾的连续数组中有k个不同的数字有多少种情况,我们把数组A看成请求序列,那么第j个请求时LRU cache的状态可以表示成一个链表,其中第k个数字的下标 i k i_k ik处就是往回追溯的第k个unique的数字,所以 i = i k i=i_k i=ik是使得[i,j]中有k个不同数字的最大的那个左边界。
左边界还可以再继续减小,直到遇到第k+1个不同数字,也就是 i k + 1 i_{k+1} ik+1处的那个数字,这时 [ i k + 1 , j ] [i_{k+1},j] [ik+1,j]之间就有k+1个数字了。
所以以A[j]为结尾的连续数组中有k个不同的数字的情况共有: i k − i k + 1 i_k-i_{k+1} ikik+1种。
因此我们可以维护一个大小为K+1的LRU cache

复制代码
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
class LinkNode(object): def __init__(self, x,y): self.val = x self.idx = y self.prev = None self.next = None class Solution(object): def subarraysWithKDistinct(self, A, K): """ :type A: List[int] :type K: int :rtype: int """ n = len(A) back,head = LinkNode(0,-1),LinkNode(n+1,n) head.next = back back.prev = head cache = {0:back} ans = 0 K += 1 for i,a in enumerate(A): if a in cache: cache[a].prev.next = cache[a].next if cache[a].next: cache[a].next.prev = cache[a].prev else: back = cache[a].prev cache[a].prev = head cache[a].next = head.next head.next.prev = cache[a] head.next = cache[a] cache[a].idx = i else: cache[a] = LinkNode(a,i) cache[a].prev = head cache[a].next = head.next head.next.prev = cache[a] head.next = cache[a] if len(cache)>K: back.prev.next = None cache.pop(back.val) back = back.prev if len(cache)==K: ans += back.prev.idx-back.idx return ans

解法二:滑动窗口

看了一下网站上给的答案,基本原理跟解法一相似,也需要维护两个值 l k l_k lk l k − 1 l_{k-1} lk1,分别是使得 [ i , j ] [i,j] [i,j]里有k个不同的数的最小的左边界。
但是采用的是类似尺取法的思想,那就是随着j增加, i k i_k ik i k + 1 i_{k+1} ik+1是递增的。

复制代码
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
class Counter(object): def __init__(self): self.cnt = {} self.num = 0 def add(self,a): self.cnt[a] = self.cnt.get(a,0)+1 if self.cnt[a]==1: self.num += 1 def remove(self,a): self.cnt[a] -= 1 if self.cnt[a] == 0: self.num -= 1 class Solution(object): def subarraysWithKDistinct(self, A, K): """ :type A: List[int] :type K: int :rtype: int """ n = len(A) ans = lk = lk1 = 0 k = Counter() k1 = Counter() for i,a in enumerate(A): k.add(a) k1.add(a) while lk<=i and k.num>K: k.remove(A[lk]) lk += 1 while lk1<=i and k1.num>=K: k1.remove(A[lk1]) lk1 += 1 ans += lk1-lk return ans

效率没有前者高

解法三:优化解法二

参考评论区@lantusky 的答案

解法二的问题是维护两个Counter很麻烦
思路见注释:

复制代码
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
class Solution(object): def subarraysWithKDistinct(self, A, K): """ :type A: List[int] :type K: int :rtype: int """ # former是使得有K个不同数字的最小边界 # latter是最大边界 ans = former = latter = 0 # freq记录了滑动窗口[latter,j]里每个数字的出现频率 freq = {} for a in A: freq[a] = freq.get(a,0) + 1 # 当窗口右边扩大一位之后引入了一个新的数字 if len(freq)==K+1: # 窗口过大,需要增大左边界以减小窗口 # 由于latter是最大的左边界,所以freq[A[latter]]一定为1,否则矛盾 # 所以freq[A[latter]]-1一定为0,那么减小窗口就相当于把它pop掉 freq.pop(A[latter]) latter += 1 # pop完之后窗口[latter+1,j]里一定只有K个不同数字了 # 所以latter+1就是最小的左边界 former = latter # 这里加一句判断是为了把窗口里unique数字小于K的情况去掉 if len(freq)==K: # 求latter的准确值 while freq[A[latter]]>1: freq[A[latter]] -= 1 latter += 1 ans += latter-former +1 return ans

最后

以上就是饱满薯片最近收集整理的关于【Leetcode】992. Subarrays with K Different Integers解法的全部内容,更多相关【Leetcode】992.内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(89)

评论列表共有 0 条评论

立即
投稿
返回
顶部