阿犇

记录生活中的点点滴滴

0%

查询差绝对值的最小值

第246场周赛 D

传送门:https://leetcode-cn.com/problems/minimum-absolute-difference-queries/

Problem

一个数组 a差绝对值的最小值 定义为:0 <= i < j < a.lengtha[i] != a[j]|a[i] - a[j]|最小值。如果 a 中所有元素都 相同 ,那么差绝对值的最小值为 -1

  • 比方说,数组 [5,**2**,**3**,7,2] 差绝对值的最小值是 |2 - 3| = 1 。注意答案不为 0 ,因为 a[i]a[j] 必须不相等。

给你一个整数数组 nums 和查询数组 queries ,其中 queries[i] = [li, ri] 。对于每个查询 i ,计算 子数组 nums[li...ri]差绝对值的最小值 ,子数组 nums[li...ri] 包含 nums 数组(下标从 0 开始)中下标在 liri 之间的所有元素(包含 liri 在内)。

请你返回 ans 数组,其中 ans[i] 是第 i 个查询的答案。

子数组 是一个数组中连续的一段元素。

|x| 的值定义为:

  • 如果 x >= 0 ,那么值为 x
  • 如果 x < 0 ,那么值为 -x

示例 1

1
2
3
4
5
6
7
输入:nums = [1,3,4,8], queries = [[0,1],[1,2],[2,3],[0,3]]
输出:[2,1,4,1]
解释:查询结果如下:
- queries[0] = [0,1]:子数组是 [1,3] ,差绝对值的最小值为 |1-3| = 2 。
- queries[1] = [1,2]:子数组是 [3,4] ,差绝对值的最小值为 |3-4| = 1 。
- queries[2] = [2,3]:子数组是 [4,8] ,差绝对值的最小值为 |4-8| = 4 。
- queries[3] = [0,3]:子数组是 [1,3,4,8] ,差的绝对值的最小值为 |3-4| = 1 。

示例 2

1
2
3
4
5
6
7
输入:nums = [4,5,2,2,7,10], queries = [[2,3],[0,2],[0,5],[3,5]]
输出:[-1,1,1,3]
解释:查询结果如下:
- queries[0] = [2,3]:子数组是 [2,2] ,差绝对值的最小值为 -1 ,因为所有元素相等。
- queries[1] = [0,2]:子数组是 [4,5,2] ,差绝对值的最小值为 |4-5| = 1 。
- queries[2] = [0,5]:子数组是 [4,5,2,2,7,10] ,差绝对值的最小值为 |4-5| = 1 。
- queries[3] = [3,5]:子数组是 [2,7,10] ,差绝对值的最小值为 |7-10| = 3 。
数据范围
1
2
3
4
2 <= nums.length <= 1e5
1 <= nums[i] <= 100
1 <= queries.length <= 2 * 1e4
0 <= li < ri < nums.length

前缀和+哈希

  • 1 <= nums[i] <= 100

数组中数据范围只有100,可以看作突破口。

预处理前缀和,我们在判断某个数时,如果出现过记为1,没有出现过记为0。

$q[i][j]$:数字$i$在前$j$位出现过多少次。

预处理前缀和:10^5*100=10^7​

预处理前缀和,可以将判断num[i]中某个数是否出现过的时间复杂度优化为$O(1)$,对每次询问判断差值最大值只需要扫一次$1-100$,共2*10^4*100=2*10^6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Solution {
public:
// q[i][j]:
int q[102][100002];
vector<int> ans;
vector<int> minDifference(vector<int>& nums, vector<vector<int>>& queries) {
// 1 <= nums[i] <= 100
// 暴力:对每次询问 2*1e4: 哈希表扫一次区间1e5,找max1e2,时间复杂度O(2*1e9)
// 优化:对每次询问 2*1e4:判断1-100每个数是否出现(可以优化到O(100)),找1e2,时间复杂度O(2*1e6)

// 处理0-100每个数是否出现过
// 对数组中的每个数x,nums[i]==x置为1,nums[i]!=x置为0;
// 预处理用前缀和O(1e5*1e2)=O(1e7)
for(int i=1;i<=100;i++){
for(int j=0;j<nums.size();j++){
int tnt=0;
if(nums[j]==i) tnt=1;
q[i][j+1]=q[i][j]+tnt;
}
}

// 可以不用vector来存,然后再遍历求Min
// 不需要额外开空间
for(int i=0;i<queries.size();i++){
int last=-1; // 上一个出现过的数
int Min=101;
int l=queries[i][0];
int r=queries[i][1];
for(int j=1;j<=100;j++){
if(q[j][r+1]-q[j][l]>0){
// 更新Min
if(last!=-1){
Min=min(Min,j-last);
}
last=j;
}
}
if(Min==101) Min=-1;
ans.push_back(Min);
}
return ans;
}
};

您的支持是我继续创作的最大动力!