comments | difficulty | edit_url | rating | source | tags | ||||
---|---|---|---|---|---|---|---|---|---|
true |
困难 |
2451 |
第 395 场周赛 Q4 |
|
给你一个整数数组 nums
。数组 nums
的 唯一性数组 是一个按元素从小到大排序的数组,包含了 nums
的所有非空 子数组 中不同元素的个数。
换句话说,这是由所有 0 <= i <= j < nums.length
的 distinct(nums[i..j])
组成的递增数组。
其中,distinct(nums[i..j])
表示从下标 i
到下标 j
的子数组中不同元素的数量。
返回 nums
唯一性数组 的 中位数 。
注意,数组的 中位数 定义为有序数组的中间元素。如果有两个中间元素,则取值较小的那个。
示例 1:
输入:nums = [1,2,3]
输出:1
解释:
nums
的唯一性数组为 [distinct(nums[0..0]), distinct(nums[1..1]), distinct(nums[2..2]), distinct(nums[0..1]), distinct(nums[1..2]), distinct(nums[0..2])]
,即 [1, 1, 1, 2, 2, 3]
。唯一性数组的中位数为 1 ,因此答案是 1 。
示例 2:
输入:nums = [3,4,3,4,5]
输出:2
解释:
nums
的唯一性数组为 [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3]
。唯一性数组的中位数为 2 ,因此答案是 2 。
示例 3:
输入:nums = [4,3,5,4]
输出:2
解释:
nums
的唯一性数组为 [1, 1, 1, 1, 2, 2, 2, 3, 3, 3]
。唯一性数组的中位数为 2 ,因此答案是 2 。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 105
我们记数组
考虑唯一性数组中,有多少个数小于等于
我们定义二分查找的左边界
函数
由于子数组越长,不同元素的个数越多,因此,我们可以利用双指针维护一个滑动窗口,使得窗口中的子数组的不同元素的个数不超过
我们枚举
时间复杂度
class Solution:
def medianOfUniquenessArray(self, nums: List[int]) -> int:
def check(mx: int) -> bool:
cnt = defaultdict(int)
k = l = 0
for r, x in enumerate(nums):
cnt[x] += 1
while len(cnt) > mx:
y = nums[l]
cnt[y] -= 1
if cnt[y] == 0:
cnt.pop(y)
l += 1
k += r - l + 1
if k >= (m + 1) // 2:
return True
return False
n = len(nums)
m = (1 + n) * n // 2
return bisect_left(range(n), True, key=check)
class Solution {
private long m;
private int[] nums;
public int medianOfUniquenessArray(int[] nums) {
int n = nums.length;
this.nums = nums;
m = (1L + n) * n / 2;
int l = 0, r = n;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
private boolean check(int mx) {
Map<Integer, Integer> cnt = new HashMap<>();
long k = 0;
for (int l = 0, r = 0; r < nums.length; ++r) {
int x = nums[r];
cnt.merge(x, 1, Integer::sum);
while (cnt.size() > mx) {
int y = nums[l++];
if (cnt.merge(y, -1, Integer::sum) == 0) {
cnt.remove(y);
}
}
k += r - l + 1;
if (k >= (m + 1) / 2) {
return true;
}
}
return false;
}
}
class Solution {
public:
int medianOfUniquenessArray(vector<int>& nums) {
int n = nums.size();
using ll = long long;
ll m = (1LL + n) * n / 2;
int l = 0, r = n;
auto check = [&](int mx) -> bool {
unordered_map<int, int> cnt;
ll k = 0;
for (int l = 0, r = 0; r < n; ++r) {
int x = nums[r];
++cnt[x];
while (cnt.size() > mx) {
int y = nums[l++];
if (--cnt[y] == 0) {
cnt.erase(y);
}
}
k += r - l + 1;
if (k >= (m + 1) / 2) {
return true;
}
}
return false;
};
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
};
func medianOfUniquenessArray(nums []int) int {
n := len(nums)
m := (1 + n) * n / 2
return sort.Search(n, func(mx int) bool {
cnt := map[int]int{}
l, k := 0, 0
for r, x := range nums {
cnt[x]++
for len(cnt) > mx {
y := nums[l]
cnt[y]--
if cnt[y] == 0 {
delete(cnt, y)
}
l++
}
k += r - l + 1
if k >= (m+1)/2 {
return true
}
}
return false
})
}
function medianOfUniquenessArray(nums: number[]): number {
const n = nums.length;
const m = Math.floor(((1 + n) * n) / 2);
let [l, r] = [0, n];
const check = (mx: number): boolean => {
const cnt = new Map<number, number>();
let [l, k] = [0, 0];
for (let r = 0; r < n; ++r) {
const x = nums[r];
cnt.set(x, (cnt.get(x) || 0) + 1);
while (cnt.size > mx) {
const y = nums[l++];
cnt.set(y, cnt.get(y)! - 1);
if (cnt.get(y) === 0) {
cnt.delete(y);
}
}
k += r - l + 1;
if (k >= Math.floor((m + 1) / 2)) {
return true;
}
}
return false;
};
while (l < r) {
const mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}