𝑰’𝒎 𝒉𝒉𝒈, 𝑰 𝒂𝒎 𝒂 𝒈𝒓𝒂𝒅𝒖𝒂𝒕𝒆 𝒔𝒕𝒖𝒅𝒆𝒏𝒕 𝒇𝒓𝒐𝒎 𝑵𝒂𝒏𝒋𝒊𝒏𝒈, 𝑪𝒉𝒊𝒏𝒂.
- 🏫 𝑺𝒉𝒄𝒐𝒐𝒍: 𝑯𝒐𝒉𝒂𝒊 𝑼𝒏𝒊𝒗𝒆𝒓𝒔𝒊𝒕𝒚
- 🌱 𝑳𝒆𝒂𝒓𝒏𝒊𝒏𝒈: 𝑰’𝒎 𝒄𝒖𝒓𝒓𝒆𝒏𝒕𝒍𝒚 𝒍𝒆𝒂𝒓𝒏𝒊𝒏𝒈 𝒅𝒆𝒔𝒊𝒈𝒏 𝒑𝒂𝒕𝒕𝒆𝒓𝒏, 𝑳𝒆𝒆𝒕𝒄𝒐𝒅𝒆, 𝒅𝒊𝒔𝒕𝒓𝒊𝒃𝒖𝒕𝒆𝒅 𝒔𝒚𝒔𝒕𝒆𝒎, 𝒎𝒊𝒅𝒅𝒍𝒆𝒘𝒂𝒓𝒆 𝒂𝒏𝒅 𝒔𝒐 𝒐𝒏.
- 💓 𝑯𝒐𝒘 𝒕𝒐 𝒓𝒆𝒂𝒄𝒉 𝒎𝒆:𝑽𝑿
- 📚 𝑴𝒚 𝒃𝒍𝒐𝒈: 𝒉𝒕𝒕𝒑𝒔://𝒉𝒉𝒈𝒚𝒚𝒅𝒔.𝒃𝒍𝒐𝒈.𝒄𝒔𝒅𝒏.𝒏𝒆𝒕/
- 💼 𝑷𝒓𝒐𝒇𝒆𝒔𝒔𝒊𝒐𝒏𝒂𝒍 𝒔𝒌𝒊𝒍𝒍𝒔:𝒎𝒚 𝒅𝒓𝒆𝒂𝒎
题解
这个题目拿到手上,一看就知道是滑动窗口题。再看看,一个篮子里面装水果,种类最多是2,很明显就是往里面塞,重复的数字只能算一个,那么就能想到用set,关键是用了set怎么从篮子里面把那个先放进来的水果给扔出去呢?
如果是从左往右扔,为什么是从左往右扔呢?
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
题目里面的意思就是有顺序,不能跳过,就是不能一下子把[low,high]=[1,2,1,1,3]里面的某一个不连续的重复数,比如这里的2全扔掉变成[2,3]。所以这里应该扔掉1,2变成[1,1,3]就能符合新的要求。但是这个从左到右对于set是比较难以把握的,因为很难判断到底扔多少个,但是我们可以知道保留多少个呀,对不对,只要满足high之前的都是同一个数就好了。也就是[1,1,3]。蓝色的就是新的符合题意的篮子。2就是需要被扔掉的那个水果,直接从篮子里面剔除,所以前面有多少个2在这一刻都已经被丢掉了,包括2之前的1,也不要了,因为要保证low,high这个区间的连续性
上代码!
public int totalFruit2(int[] fruits) {
int n = fruits.length;
int high = 0;
int max = -1;
Set<Integer> set = new HashSet<>();
int low = 0;
while (high < n) {
set.add(fruits[high]);
if (set.size() > 2) { // 丢水果的过程
low = high - 1;
while (fruits[low - 1] == fruits[low]) {
low--;
}
set.remove(fruits[low - 1]);
}
max = Math.max(max, high - low + 1); // @1
high++;
}
return max;
}
@1:会对每一次的[low,high]范围进行判断,这样就不会漏掉set.size==2的时候里面的各种情况,比如[1,2,1]或者是[1,2,1,1]都会被计算的,直到遇见[1,2,1,1,3],进行判断set.size() > 2
直接给出下一个满足题意的[low,high]出来。注意我们讨论的[low,high]都是闭区间。
这个方法来自评论区的一个兄弟,也是我的方法,但是我在篮子出现3个怎么扔水果的地方,解不出来。
官解
官解和上面的思想一样,但是通过一个map实现的从左到右扔水果的过程,代码如下:
public int totalFruit(int[] fruits) {
int n = fruits.length;
int low = 0, high = 0;
int max = -1;
Map<Integer, Integer> map = new HashMap<>();
while (high < n) {
map.put(fruits[high], map.getOrDefault(fruits[high], 0) + 1);
while (map.size() > 2) { // 丢水果的过程
map.put(fruits[low], map.get(fruits[low]) - 1);
if (map.get(fruits[low]) == 0) {
map.remove(fruits[low]);
}
low++;
}
max = Math.max(max, high - low + 1);
high++;
}
return max;
}