forked from azl397985856/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
robot
committed
Jun 23, 2021
1 parent
0c54f9a
commit 268ab5e
Showing
3 changed files
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
## 题目地址(1906. 查询差绝对值的最小值) | ||
|
||
https://leetcode-cn.com/problems/minimum-absolute-difference-queries/ | ||
|
||
## 题目描述 | ||
|
||
``` | ||
一个数组 a 的 差绝对值的最小值 定义为:0 <= i < j < a.length 且 a[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 开始)中下标在 li 和 ri 之间的所有元素(包含 li 和 ri 在内)。 | ||
请你返回 ans 数组,其中 ans[i] 是第 i 个查询的答案。 | ||
子数组 是一个数组中连续的一段元素。 | ||
|x| 的值定义为: | ||
如果 x >= 0 ,那么值为 x 。 | ||
如果 x < 0 ,那么值为 -x 。 | ||
示例 1: | ||
输入: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: | ||
输入: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 。 | ||
提示: | ||
2 <= nums.length <= 10^5 | ||
1 <= nums[i] <= 100 | ||
1 <= queries.length <= 2 * 10^4 | ||
0 <= li < ri < nums.length | ||
``` | ||
|
||
## 前置知识 | ||
|
||
- 前缀和 | ||
- 离散化 | ||
|
||
## 公司 | ||
|
||
- 暂无 | ||
|
||
## 思路 | ||
|
||
由于需要查询任意区间 [ql,qr] 的差的最小值。因此一种简单的思路是对 nums 进行一次排序,之后遍历 [ql,qr] 的所有相邻差,并取最小的即可。这种做法时间复杂度为排序 $nlogn$ + 查询 $n^2$,代入题目数据范围 $2 <= nums.length <= 10^5$,则必然超时。 | ||
|
||
一种优化的思路是对 nums 的数据进行离散化,即将值映射到一个大小为 nums 值域大小的数组(由于 1 <= nums[i] <= 100 ,因此对于这道题来说至于大小就是 100)。这样通过遍历值域数组就可以得到最小绝对值差。由于值域大小最多是 100,相比于 $10^5$ 是巨大优化。 | ||
|
||
不过值域数组不含索引信息,因此我想求区间 [ql,qr] 的差的最小值则无法直接做到,我们只能求区间 [0,n-1] 的差的最小值。 | ||
|
||
那怎么办呢? | ||
|
||
我们建立 n 个值域数组,即对每一个索引 i 都建立一个值域数组。这样区间 [ql,qr]的值就可以通过前缀和求得。比如 : | ||
|
||
```py | ||
for i in range(1, 101): | ||
v = pres[qr+1][i] - pres[ql][i] | ||
``` | ||
|
||
v 就是 i 在 [ql,qr] 的出现次数。 | ||
|
||
也就是说**我们可以建议二维数组 pre[i][j] 表示数组 nums 前 i 项 j 出现的次数**,这样可以通过前缀和求出任意区间任意数出现次数。 | ||
|
||
剩下的就容易了,具体参考下方代码。 | ||
|
||
这种做法本质上空间换时间,即使用值域的空间大小换取嵌套 n 循环的实际,是一种典型的取舍。也就是说如果题目值域很大,比如 $10^7$ ,那就不适合使用此算法了。 | ||
|
||
## 关键点 | ||
|
||
- 同时对索引和值建立前缀和,即建立二维前缀和 | ||
|
||
## 代码 | ||
|
||
- 语言支持:Python3 | ||
|
||
Python3 Code: | ||
|
||
```python | ||
|
||
class Solution: | ||
def minDifference(self, nums: List[int], queries: List[List[int]]) -> List[int]: | ||
ans = [] | ||
n = len(nums) | ||
pres = [[0] * 101] | ||
for i, num in enumerate(nums): | ||
pres.append(pres[-1].copy()) | ||
pres[-1][num] += 1 | ||
|
||
for ql, qr in queries: | ||
pre = -100 | ||
cur = 100 | ||
for i in range(1, 101): | ||
if pres[qr+1][i] - pres[ql][i] > 0: | ||
cur = min(cur, i - pre) | ||
pre = i | ||
if cur >= 100: ans.append(-1) | ||
else: ans.append(cur) | ||
return ans | ||
|
||
``` | ||
|
||
**复杂度分析** | ||
|
||
令 n 为数组长度,q 为 queries 长度,v 为 nums 取值范围(这里是 100)。 | ||
|
||
- 时间复杂度:$O(nvq)$ | ||
- 空间复杂度:$O(nv)$ | ||
|
||
> 此题解由 [力扣刷题插件](https://leetcode-pp.github.io/leetcode-cheat/?tab=solution-template) 自动生成。 | ||
力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~ | ||
|
||
以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 | ||
|
||
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。 | ||
|
||
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfcuzagjalj30p00dwabs.jpg) |