2023/10/13大约 4 分钟
一、题目描述
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组fruits表示,其中fruits[i]是第i棵树上的水果种类。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
- 你只有两个篮子,并且每个篮子只能装单一类型的水果。每个篮子能够装的水果总量没有限制。
- 你可以选择任意一棵树开始采摘,你必须从每棵树(包括开始采摘的树)上恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
- 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组fruits,返回你可以收集的水果的最大数目。
示例 1:
 输入: fruits = [1, 2, 1]
 输出: 3
 解释: 可以采摘全部3棵树。
示例 2:
 输入: fruits = [0, 1, 2, 2]
 输出: 3
 解释: 可以采摘[1, 2, 2]这三棵树。如果从第一棵树开始采摘,则只能采摘[0, 1]这两棵树。
示例 3:
 输入: fruits = [1, 2, 3, 2, 2]
 输出: 4
 解释: 可以采摘[2, 3, 2, 2]这四棵树。如果从第一棵树开始采摘,则只能采摘[1, 2]这两棵树。
示例 4:
 输入: fruits = [3, 3, 3, 1, 2, 1, 1, 2, 3, 3, 4]
 输出: 5
 解释: 可以采摘[1, 2, 1, 1, 2]这五棵树。
提示:
- 1 <= fruits.length <= 10⁵
- 0 <= fruits[i] < fruits.length
相关主题:
- 数组
- 哈希表
- 滑动窗口
二、题解
方法 1: 暴力解法
Rust
/// Time Limit Exceeded
///
/// Time Complexity: O(n^3)
/// Space Complexity: O(1)
pub fn total_fruit(fruits: Vec<i32>) -> i32 {
    let len = fruits.len();
    let mut set = HashSet::new();
    for width in (2..=len).rev() {
        let mut left = 0;
        let mut right = width;
        while right <= len {
            for i in left..right {
                set.insert(fruits[i]);
                if set.len() > 2 {
                    break;
                }
            }
            if set.len() == 2 {
                return width as i32;
            }
            left += 1;
            right = left + width;
            set.clear();
        }
    }
    len as i32
}Java
public int totalFruit(int[] fruits) {
    HashSet<Integer> set = new HashSet<>();
    for (int width = fruits.length; width >= 2; width--) {
        int left = 0;
        int right = width;
        while (right <= fruits.length) {
            for (int i = left; i < right; i++) {
                set.add(fruits[i]);
                if (set.size() > 2) {
                    break;
                }
            }
            if (set.size() == 2) {
                return width;
            }
            left++;
            right = left + width;
            set.clear();
        }
    }
    
    return fruits.length;
}Go
func totalFruit(fruits []int) int {
    size := len(fruits)
    set := make(map[int]struct{})
    for width := size; width >= 2; width-- {
        left, right := 0, width
        for right <= size {
            for i := left; i < right; i++ {
                set[fruits[i]] = struct{}{}
                if len(set) > 2 {
                    break
                }
            }
            if len(set) == 2 {
                return width
            }
            left++
            right = left + width
            clear(set)
        }
    }
    return size
}C#
public int TotalFruit(int[] fruits)
{
    HashSet<int> set = new HashSet<int>();
    for (int width = fruits.Length; width >= 2; --width)
    {
        int left = 0;
        int right = width;
        while (right <= fruits.Length)
        {
            for (int i = left; i < right; ++i)
            {
                set.Add(fruits[i]);
                if (set.Count > 2)
                    break;
            }
            if (set.Count == 2)
                return width;
            ++left;
            right = left + width;
            set.Clear();
        }
    }
    return fruits.Length;
}C++
int totalFruit(vector<int>& fruits) {
    auto size = fruits.size();
    unordered_set<int> set;
    for (auto width = size; width >= 2; --width) {
        auto left = 0;
        auto right = width;
        while (right <= size) {
            for (auto i = left; i < right; ++i) {
                set.insert(fruits[i]);
                if (set.size() > 2)
                    break;
            }
            if (set.size() == 2)
                return width;
            
            ++left;
            right = left + width;
            set.clear();
        }
    }
    return size;
}方法 2: 滑动窗口
Rust
pub fn total_fruit(fruits: Vec<i32>) -> i32 {
    let mut map = HashMap::new();
    let mut left = 0;
    let mut res = 0;
    for right in 0..fruits.len() {
        map.entry(fruits[right])
            .and_modify(|v| *v += 1)
            .or_insert(1);
        while map.len() > 2 {
            if let Some(v) = map.get_mut(&fruits[left]) {
                *v -= 1;
            }
            if map[&fruits[left]] == 0 {
                map.remove(&fruits[left]);
            }
            left += 1;
        }
        res = std::cmp::max(res, right - left + 1);
    }
    res as i32
}Java
public int totalFruit(int[] fruits) {
    int left = 0;
    int res = 0;
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int right = 0; right < fruits.length; right++) {
        map.put(fruits[right], map.getOrDefault(fruits[right], 0) + 1);
        while (map.size() > 2) {
            map.put(fruits[left], map.get(fruits[left]) - 1);
            if (map.get(fruits[left]) == 0) {
                map.remove(fruits[left]);
            }
            left++;
        }
        res = Math.max(res, right - left + 1);
    }
    return res;
}Go
func totalFruit(fruits []int) int {
    left, res := 0, 0
    _map := make(map[int]int)
    for right := 0; right < len(fruits); right++ {
        _map[fruits[right]]++
        for len(_map) > 2 {
            _map[fruits[left]]--
            if _map[fruits[left]] == 0 {
                delete(_map, fruits[left])
            }
            left++
        }
        res = max(res, right-left+1)
    }
    return res
}C#
public int TotalFruit(int[] fruits)
{
    int res = 0;
    int left = 0;
    Dictionary<int, int> map = new Dictionary<int, int>();
    for (int right = 0; right < fruits.Length; right++)
    {
        if (map.TryGetValue(fruits[right], out var count))
            map[fruits[right]] = count + 1;
        else
            map[fruits[right]] = 1;
        
        while (map.Count > 2)
        {
            map[fruits[left]]--;
            if (map[fruits[left]] == 0)
                map.Remove(fruits[left]);
            ++left;
        }
        res = Math.Max(res, right - left + 1);
    }
    
    return res;
}C++
int totalFruit(vector<int>& fruits) {
    int res = 0;
    int left = 0;
    unordered_map<int, int> map;
    for (auto right = 0; right < fruits.size(); ++right) {
        map[fruits[right]]++;
        while (map.size() > 2) {
            map[fruits[left]]--;
            if (map[fruits[left]] == 0)
                map.erase(fruits[left]);
            ++left;
        }
        res = std::max(res, right - left + 1);
    }
    return res;
}