有华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳od1336
了解算法冲刺训练
LeetCode2670、找出不同元素数目差数组
给你一个下标从 0 开始的数组 nums
,数组长度为 n
。
nums
的 不同元素数目差 数组可以用一个长度为 n
的数组 diff
表示,其中 diff[i]
等于前缀 nums[0, ..., i]
中不同元素的数目 减去 后缀 nums[i + 1, ..., n - 1]
中不同元素的数目。
返回 nums
的 不同元素数目差 数组。
注意 nums[i, ..., j]
表示 nums
的一个从下标 i
开始到下标 j
结束的子数组(包含下标 i
和 j
对应元素)。特别需要说明的是,如果 i > j
,则 nums[i, ..., j]
表示一个空子数组。
示例 1:
输入:nums = [1,2,3,4,5]
输出:[-3,-1,1,3,5]
解释: 对于 i = 0,前缀中有 1 个不同的元素,而在后缀中有 4 个不同的元素。因此,diff[0] = 1 - 4 = -3 。 对于 i = 1,前缀中有 2 个不同的元素,而在后缀中有 3 个不同的元素。因此,diff[1] = 2 - 3 = -1 。 对于 i = 2,前缀中有 3 个不同的元素,而在后缀中有 2 个不同的元素。因此,diff[2] = 3 - 2 = 1 。 对于 i = 3,前缀中有 4 个不同的元素,而在后缀中有 1 个不同的元素。因此,diff[3] = 4 - 1 = 3 。 对于 i = 4,前缀中有 5 个不同的元素,而在后缀中有 0 个不同的元素。因此,diff[4] = 5 - 0 = 5 。
示例 2:
输入:nums = [3,2,3,4,2]
输出:[-2,-1,0,2,3]
解释: 对于 i = 0,前缀中有 1 个不同的元素,而在后缀中有 3 个不同的元素。因此,diff[0] = 1 - 3 = -2 。 对于 i = 1,前缀中有 2 个不同的元素,而在后缀中有 3 个不同的元素。因此,diff[1] = 2 - 3 = -1 。 对于 i = 2,前缀中有 2 个不同的元素,而在后缀中有 2 个不同的元素。因此,diff[2] = 2 - 2 = 0 。 对于 i = 3,前缀中有 3 个不同的元素,而在后缀中有 1 个不同的元素。因此,diff[3] = 3 - 1 = 2 。 对于 i = 4,前缀中有 3 个不同的元素,而在后缀中有 0 个不同的元素。因此,diff[4] = 3 - 0 = 3 。
提示:
1 <= n == nums.length <= 50
1 <= nums[i] <= 50
本题的数据量很低,O(N^2)
的暴力解肯定能过。略去不表。
接下来主要讨论O(N)
复杂度的解法。
对于特定位置i
,前缀和后缀所包含的不同元素的个数是分开计算的。故分别讨论如何计算前缀和后缀的情况。
考虑从左往右遍历下标i
。
这个比较容易想到,直接用自带去重功能的哈希集合来完成。
遍历i
的过程中,将元素nums[i]
加入哈希集合set_left
,此时前缀包含的不同元素的个数即为len(set_left)
后缀就没办法用哈希集合来完成了,因为在遍历到i
的时候,我们无法得知在i
的右边是否还存在和nums[i]
相同的元素。
但是我们可以知道,如果i
的右边不存在和nums[i]
相同的元素,那么i就是元素nums[i]
出现在数组nums
中的最后一个下标。
因此我们可以在遍历i
之前,预处理一个哈希表dic_last_idx
,用于储存每一个元素num
在nums
中最后出现的下标。另外初始化一个变量right
,用于表示后缀中不重复的元素个数。
在遍历过程中,一旦发现i == dic_last_idx[nums[i]]
,说明此时i
的右边已经没有其他重复的同一元素,这意味着在下标i
的后缀中,所包含的不同元素的个数减少1
,即right -= 1
前缀和后缀的情况都讨论完毕之后,存在ans[i] = len(set_left) - right
成立
class Solution:
def distinctDifferenceArray(self, nums: List[int]) -> List[int]:
n = len(nums)
ans = [0] * n
set_left = set()
dic_last_idx = dict()
for i, num in enumerate(nums):
dic_last_idx[num] = i
right = len(dic_last_idx)
for i, num in enumerate(nums):
set_left.add(num)
if dic_last_idx[num] == i:
right -= 1
ans[i] = len(set_left) - right
return ans
class Solution {
public int[] distinctDifferenceArray(int[] nums) {
int n = nums.length;
int[] ans = new int[n];
Set<Integer> setLeft = new HashSet<>();
Map<Integer, Integer> dicLastIdx = new HashMap<>();
int right = 0;
for (int i = 0; i < n; i++) {
dicLastIdx.put(nums[i], i);
}
right = dicLastIdx.size();
for (int i = 0; i < n; i++) {
setLeft.add(nums[i]);
if (dicLastIdx.get(nums[i]) == i) {
right -= 1;
}
ans[i] = setLeft.size() - right;
}
return ans;
}
}
class Solution {
public:
vector<int> distinctDifferenceArray(vector<int>& nums) {
int n = nums.size();
vector<int> ans(n, 0);
unordered_set<int> setLeft;
unordered_map<int, int> dicLastIdx;
int right = 0;
for (int i = 0; i < n; i++) {
dicLastIdx[nums[i]] = i;
}
right = dicLastIdx.size();
for (int i = 0; i < n; i++) {
setLeft.insert(nums[i]);
if (dicLastIdx[nums[i]] == i) {
right -= 1;
}
ans[i] = setLeft.size() - right;
}
return ans;
}
};
时间复杂度:O(N)
。仅需一次遍历数组
空间复杂度:O(N)
。哈希表、哈希集合所占空间
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
绿色聊天软件戳 od1336
了解更多