高级农民
- 积分
- 4142
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2017-1-22
- 最后登录
- 1970-1-1
|
LC. 3471. Find the Largest Almost Missing Integer
You are given an integer array nums and an integer k.
An integer x is almost missing from nums if x appears in exactly one subarray of size k within nums.
Return the largest almost missing integer from nums. If no such integer exists, return -1.
A subarray is a contiguous sequence of elements within an array.
Example 1:
Input: nums = [3,9,2,1,7], k = 3
Output: 7
Explanation:
1 appears in 2 subarrays of size 3: [9, 2, 1] and [2, 1, 7].
2 appears in 3 subarrays of size 3: [3, 9, 2], [9, 2, 1], [2, 1, 7].
3 appears in 1 subarray of size 3: [3, 9, 2].
7 appears in 1 subarray of size 3: [2, 1, 7].
9 appears in 2 subarrays of size 3: [3, 9, 2], and [9, 2, 1].
We return 7 since it is the largest integer that appears in exactly one subarray of size k.
Example 2:
Input: nums = [3,9,7,2,1,7], k = 4
Output: 3
Explanation:
1 appears in 2 subarrays of size 4: [9, 7, 2, 1], [7, 2, 1, 7].
2 appears in 3 subarrays of size 4: [3, 9, 7, 2], [9, 7, 2, 1], [7, 2, 1, 7].
3 appears in 1 subarray of size 4: [3, 9, 7, 2].
7 appears in 3 subarrays of size 4: [3, 9, 7, 2], [9, 7, 2, 1], [7, 2, 1, 7].
9 appears in 2 subarrays of size 4: [3, 9, 7, 2], [9, 7, 2, 1].
We return 3 since it is the largest and only integer that appears in exactly one subarray of size k.
Example 3:
Input: nums = [0,0], k = 1
Output: -1
Explanation:
There is no integer that appears in only one subarray of size 1.
Constraints:
1 <= nums.length <= 50
0 <= nums[i] <= 50
1 <= k <= nums.length
1. 拆解题意与核心规律题目要求找出一个刚好只在 1 个长度为 $k$ 的子数组中出现过的最大整数。通过分析一个元素会被多少个长度为 $k$ 的子数组覆盖,我们可以得出三种情况(这也是你代码里的核心逻辑):$k == n$:整个数组就只有 1 个长度为 $k$ 的子数组。所以所有元素都只出现在这 1 个子数组里,直接返回 max(nums) 即可。$k == 1$:子数组长度为 1,意味着如果一个数在 nums 里出现了多次,它就会出现在多个子数组里。所以我们要找的其实就是在原数组中只出现过 1 次的最大元素。$1 < k < n$(重点):任何在中间位置(索引 $0 < i < n-1$)的元素,必定会被至少两个长度为 $k$ 的子数组覆盖。只有最左边 nums[0] 和最右边 nums[n-1],且它们在整个数组中全局频次为 1 的情况下,它们才会被刚好 1 个子数组(最左边的子数组 / 最右边的子数组)覆盖。所以这个情况的候选人,只有可能是 nums[0] 和 nums[-1]。你的思路完全正确且是最优的!- class Solution:
- def largestInteger(self, nums: List[int], k: int) -> int:
- if len(nums) == k: return max(nums)
- if k == 1:
- freq = Counter(nums)
- keys = list(freq.keys())
- keys.sort()
- for i in range(len(keys)-1, -1, -1):
- if freq[keys[i]] == 1:
- return keys[i]
- return -1
- freq = Counter(nums)
- ans = []
- if freq[nums[0]] == 1: ans.append(nums[0])
- if freq[nums[-1]] == 1: ans.append(nums[-1])
- if not ans:
- return -1
- else:
- return max(ans)
-
复制代码 优化
把求 k==1 时的最大值简化成了一行:max((x for x in freq if freq[x] == 1), default=-1)。不用去排序然后再倒序遍历,max() 底层也是 $O(N)$,而且代码极其清晰。去掉了不必要的 keys 列表转换,减少了空间复杂度。把最后的 ans 列表改为了一个单纯的整数变量比较,逻辑更紧凑。- from typing import List
- from collections import Counter
- class Solution:
- def largestInteger(self, nums: List[int], k: int) -> int:
- n = len(nums)
- # 情况 1:k 等于数组长度
- if k == n:
- return max(nums)
-
- freq = Counter(nums)
-
- # 情况 2:k 等于 1,找全局只出现 1 次的最大值
- if k == 1:
- # 生成器表达式过滤频次为 1 的数,default=-1 避免报错
- return max((x for x in freq if freq[x] == 1), default=-1)
- # 情况 3:1 < k < n,候选人只有 nums[0] 和 nums[-1]
- ans = -1
- if freq[nums[0]] == 1:
- ans = max(ans, nums[0])
- if freq[nums[-1]] == 1:
- ans = max(ans, nums[-1])
-
- return ans
复制代码 通用解法(滑动窗口 / 暴力模拟)
因为这题数据范围只有 $N \le 50$,暴力模拟每一个滑动窗口其实是 $O(N \cdot K)$ 的复杂度,在 $50 \times 50 = 2500$ 次操作内,这不仅没问题,而且是非常通用的算法模型。通用解法代码:- class Solution:
- def largestInteger(self, nums: List[int], k: int) -> int:
- n = len(nums)
- # 统计每个数字出现在了多少个【不同的】子数组中
- subarray_count = Counter()
-
- # 遍历所有长度为 k 的子数组起始点
- for i in range(n - k + 1):
- window = nums[i : i+k]
- # 同一个子数组内的重复元素只算一次,所以用 set 去重
- for num in set(window):
- subarray_count[num] += 1
-
- # 找出只出现在 1 个子数组中的最大值
- return max((num for num, count in subarray_count.items() if count == 1), default=-1)
复制代码 |
|