Skip to content

Commit 268ab5e

Browse files
author
robot
committed
feat: $1906
1 parent 0c54f9a commit 268ab5e

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
395395
- [1737. 满足三条件之一需改变的最少字符数](./problems/1737.change-minimum-characters-to-satisfy-one-of-three-conditions.md)
396396
- [1834. 单线程 CPU](./problems/1834.single-threaded-cpu.md)
397397
- [1899. 合并若干三元组以形成目标三元组](./problems/1899.merge-triplets-to-form-target-triplet.md) 👍
398+
- [1906. 查询差绝对值的最小值](./problems/1906.minimum-absolute-difference-queries.md)
398399

399400
### 困难难度题目合集
400401

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@
253253
- [1737. 满足三条件之一需改变的最少字符数](./problems/1737.change-minimum-characters-to-satisfy-one-of-three-conditions.md) 👍
254254
- [1834. 单线程 CPU](./problems/1834.single-threaded-cpu.md) 🆕
255255
- [1899. 合并若干三元组以形成目标三元组](./problems/1899.merge-triplets-to-form-target-triplet.md) 👍
256+
- [1906. 查询差绝对值的最小值](./problems/1906.minimum-absolute-difference-queries.md)
256257

257258
- [第六章 - 高频考题(困难)](collections/hard.md)
258259

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
## 题目地址(1906. 查询差绝对值的最小值)
2+
3+
https://leetcode-cn.com/problems/minimum-absolute-difference-queries/
4+
5+
## 题目描述
6+
7+
```
8+
一个数组 a 的 差绝对值的最小值 定义为:0 <= i < j < a.length 且 a[i] != a[j] 的 |a[i] - a[j]| 的 最小值。如果 a 中所有元素都 相同 ,那么差绝对值的最小值为 -1 。
9+
10+
比方说,数组 [5,2,3,7,2] 差绝对值的最小值是 |2 - 3| = 1 。注意答案不为 0 ,因为 a[i] 和 a[j] 必须不相等。
11+
12+
给你一个整数数组 nums 和查询数组 queries ,其中 queries[i] = [li, ri] 。对于每个查询 i ,计算 子数组 nums[li...ri] 中 差绝对值的最小值 ,子数组 nums[li...ri] 包含 nums 数组(下标从 0 开始)中下标在 li 和 ri 之间的所有元素(包含 li 和 ri 在内)。
13+
14+
请你返回 ans 数组,其中 ans[i] 是第 i 个查询的答案。
15+
16+
子数组 是一个数组中连续的一段元素。
17+
18+
|x| 的值定义为:
19+
20+
如果 x >= 0 ,那么值为 x 。
21+
如果 x < 0 ,那么值为 -x 。
22+
23+
 
24+
25+
示例 1:
26+
27+
输入:nums = [1,3,4,8], queries = [[0,1],[1,2],[2,3],[0,3]]
28+
输出:[2,1,4,1]
29+
解释:查询结果如下:
30+
- queries[0] = [0,1]:子数组是 [1,3] ,差绝对值的最小值为 |1-3| = 2 。
31+
- queries[1] = [1,2]:子数组是 [3,4] ,差绝对值的最小值为 |3-4| = 1 。
32+
- queries[2] = [2,3]:子数组是 [4,8] ,差绝对值的最小值为 |4-8| = 4 。
33+
- queries[3] = [0,3]:子数组是 [1,3,4,8] ,差的绝对值的最小值为 |3-4| = 1 。
34+
35+
36+
示例 2:
37+
38+
输入:nums = [4,5,2,2,7,10], queries = [[2,3],[0,2],[0,5],[3,5]]
39+
输出:[-1,1,1,3]
40+
解释:查询结果如下:
41+
- queries[0] = [2,3]:子数组是 [2,2] ,差绝对值的最小值为 -1 ,因为所有元素相等。
42+
- queries[1] = [0,2]:子数组是 [4,5,2] ,差绝对值的最小值为 |4-5| = 1 。
43+
- queries[2] = [0,5]:子数组是 [4,5,2,2,7,10] ,差绝对值的最小值为 |4-5| = 1 。
44+
- queries[3] = [3,5]:子数组是 [2,7,10] ,差绝对值的最小值为 |7-10| = 3 。
45+
46+
47+
 
48+
49+
提示:
50+
51+
2 <= nums.length <= 10^5
52+
1 <= nums[i] <= 100
53+
1 <= queries.length <= 2 * 10^4
54+
0 <= li < ri < nums.length
55+
```
56+
57+
## 前置知识
58+
59+
- 前缀和
60+
- 离散化
61+
62+
## 公司
63+
64+
- 暂无
65+
66+
## 思路
67+
68+
由于需要查询任意区间 [ql,qr] 的差的最小值。因此一种简单的思路是对 nums 进行一次排序,之后遍历 [ql,qr] 的所有相邻差,并取最小的即可。这种做法时间复杂度为排序 $nlogn$ + 查询 $n^2$,代入题目数据范围 $2 <= nums.length <= 10^5$,则必然超时。
69+
70+
一种优化的思路是对 nums 的数据进行离散化,即将值映射到一个大小为 nums 值域大小的数组(由于 1 <= nums[i] <= 100 ,因此对于这道题来说至于大小就是 100)。这样通过遍历值域数组就可以得到最小绝对值差。由于值域大小最多是 100,相比于 $10^5$ 是巨大优化。
71+
72+
不过值域数组不含索引信息,因此我想求区间 [ql,qr] 的差的最小值则无法直接做到,我们只能求区间 [0,n-1] 的差的最小值。
73+
74+
那怎么办呢?
75+
76+
我们建立 n 个值域数组,即对每一个索引 i 都建立一个值域数组。这样区间 [ql,qr]的值就可以通过前缀和求得。比如 :
77+
78+
```py
79+
for i in range(1, 101):
80+
v = pres[qr+1][i] - pres[ql][i]
81+
```
82+
83+
v 就是 i 在 [ql,qr] 的出现次数。
84+
85+
也就是说**我们可以建议二维数组 pre[i][j] 表示数组 nums 前 i 项 j 出现的次数**,这样可以通过前缀和求出任意区间任意数出现次数。
86+
87+
剩下的就容易了,具体参考下方代码。
88+
89+
这种做法本质上空间换时间,即使用值域的空间大小换取嵌套 n 循环的实际,是一种典型的取舍。也就是说如果题目值域很大,比如 $10^7$ ,那就不适合使用此算法了。
90+
91+
## 关键点
92+
93+
- 同时对索引和值建立前缀和,即建立二维前缀和
94+
95+
## 代码
96+
97+
- 语言支持:Python3
98+
99+
Python3 Code:
100+
101+
```python
102+
103+
class Solution:
104+
def minDifference(self, nums: List[int], queries: List[List[int]]) -> List[int]:
105+
ans = []
106+
n = len(nums)
107+
pres = [[0] * 101]
108+
for i, num in enumerate(nums):
109+
pres.append(pres[-1].copy())
110+
pres[-1][num] += 1
111+
112+
for ql, qr in queries:
113+
pre = -100
114+
cur = 100
115+
for i in range(1, 101):
116+
if pres[qr+1][i] - pres[ql][i] > 0:
117+
cur = min(cur, i - pre)
118+
pre = i
119+
if cur >= 100: ans.append(-1)
120+
else: ans.append(cur)
121+
return ans
122+
123+
```
124+
125+
**复杂度分析**
126+
127+
令 n 为数组长度,q 为 queries 长度,v 为 nums 取值范围(这里是 100)。
128+
129+
- 时间复杂度:$O(nvq)$
130+
- 空间复杂度:$O(nv)$
131+
132+
> 此题解由 [力扣刷题插件](https://leetcode-pp.github.io/leetcode-cheat/?tab=solution-template) 自动生成。
133+
134+
力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~
135+
136+
以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
137+
138+
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
139+
140+
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfcuzagjalj30p00dwabs.jpg)

0 commit comments

Comments
 (0)