leetcode
leetcode 2351 ~ 2400
找出最长等值子数组

找出最长等值子数组

难度:

标签:

题目描述

You are given a 0-indexed integer array nums and an integer k.

A subarray is called equal if all of its elements are equal. Note that the empty subarray is an equal subarray.

Return the length of the longest possible equal subarray after deleting at most k elements from nums.

A subarray is a contiguous, possibly empty sequence of elements within an array.

 

Example 1:

Input: nums = [1,3,2,3,1,3], k = 3
Output: 3
Explanation: It's optimal to delete the elements at index 2 and index 4.
After deleting them, nums becomes equal to [1, 3, 3, 3].
The longest equal subarray starts at i = 1 and ends at j = 3 with length equal to 3.
It can be proven that no longer equal subarrays can be created.

Example 2:

Input: nums = [1,1,2,2,1,1], k = 2
Output: 4
Explanation: It's optimal to delete the elements at index 2 and index 3.
After deleting them, nums becomes equal to [1, 1, 1, 1].
The array itself is an equal subarray, so the answer is 4.
It can be proven that no longer equal subarrays can be created.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= nums.length
  • 0 <= k <= nums.length

代码结果

运行时间: 311 ms, 内存: 36.6 MB


/*
 * 题目思路:
 * 1. 使用滑动窗口的方法来找到最长的等值子数组。
 * 2. 使用Java Stream API来处理数组中的频率统计和窗口移动。
 * 3. 计算需要删除的元素数量,如果超过k则移动left指针,直到删除的元素数量小于等于k。
 * 4. 记录并更新最大等值子数组的长度。
 */

import java.util.*;
import java.util.stream.Collectors;

public class Solution {
    public int longestEqualSubarray(int[] nums, int k) {
        Map<Integer, Long> countMap = new HashMap<>();
        int maxFreq = 0;
        int maxLength = 0;
        int left = 0;

        for (int right = 0; right < nums.length; right++) {
            countMap.put(nums[right], countMap.getOrDefault(nums[right], 0L) + 1);
            maxFreq = countMap.values().stream().mapToInt(Long::intValue).max().orElse(0);

            if (right - left + 1 - maxFreq > k) {
                countMap.put(nums[left], countMap.get(nums[left]) - 1);
                left++;
            }

            maxLength = Math.max(maxLength, right - left + 1);
        }

        return maxLength;
    }
}

解释

方法:

这个题解的基本思路是使用一个哈希表(通过defaultdict实现)来存储数组中每个元素的所有索引。接着,对于哈希表中的每个元素,使用一个滑动窗口的方法来找到包含最多k个非该元素的最长子数组。具体来说,哈希表的键是元素值,值是该元素在数组中出现的所有位置的索引列表。然后,对于每个键值对,使用双指针技术(滑动窗口)来计算在最多删除k个其他元素的条件下,可以形成的最长等值子数组的长度。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在解决这个问题时,为什么选择使用哈希表来存储元素及其索引,而不是其他数据结构如数组或链表?
哈希表(或字典)提供高效的查找和插入操作,平均时间复杂度为O(1)。使用哈希表可以快速访问任何元素的所有索引,这对于算法中频繁的元素查找和索引访问非常有用。相比之下,如果使用数组或链表,查找特定值的所有出现或其索引可能需要O(n)的时间复杂度,这会显著增加算法的总体运行时间。因此,哈希表是一种更优的数据结构选择。
🦆
哈希表中的键是元素值,值是索引列表。在实现滑动窗口时,如何有效处理索引列表以确保窗口内最多只有k个非当前元素?
在滑动窗口实现中,维护两个指针i和j,分别代表窗口的结束和开始位置。通过遍历索引列表,指针i逐步向右移动,扩大窗口。当窗口中非当前元素的数量超过k时(计算方法是窗口长度减去窗口中当前元素的数量,即d[i]-d[j]+1 - (i-j+1)),开始移动指针j以缩小窗口,直到非当前元素的数量不超过k为止。这种方法确保了每次计算窗口长度时,窗口内最多包含k个非当前元素。
🦆
在更新最长等值子数组长度时,为什么选择使用`max(res, i - j + 1)`来计算长度?这里的计算逻辑是怎样的?
`max(res, i - j + 1)`这个表达式用于更新并保持最长等值子数组的最大长度。这里,`i - j + 1`计算的是当前考虑的等值子数组的长度,从索引j到i。每次遍历新的索引i时,都会用当前子数组的长度与之前记录的最大长度res进行比较,并更新res为两者之间的较大值。这确保了res始终保持为遍历过程中遇到的最长等值子数组的长度。
🦆
在实际编码中,如果数组`nums`中存在重复元素的索引列表长度远小于数组长度,这种情况是否会影响算法的效率?
如果某个元素的出现次数较少,那么其索引列表长度较小,这对算法的效率是有利的。因为对于这些元素,滑动窗口操作需要处理的数据量减少,从而减少了计算量。然而,如果数组中大部分元素都是这种情况,那么虽然单个元素处理速度快,但需要处理的元素种类可能很多,从而增加总的处理时间。总体来说,算法的效率与数组中元素的分布和重复情况有关,索引列表较短通常有助于提高效率。

相关问题