leetcode-7022限制条件下元素之间的最小绝对差
leetcode-7022
这道题是358周赛的第三题,当时没做出来,后来弄明白了,记录一下。
#题目
给你一个下标从 0 开始的整数数组 nums
和一个整数 x
。
请你找到数组中下标距离至少为 x
的两个元素的 差值绝对值 的 最小值 。
换言之,请你找到两个下标 i
和 j
,满足 abs(i - j) >= x
且 abs(nums[i] - nums[j])
的值最小。
请你返回一个整数,表示下标距离至少为 x
的两个元素之间的差值绝对值的 最小值 。
示例 1:
1 | 输入:nums = [4,3,2,4], x = 2 |
示例 2:
1 | 输入:nums = [5,3,2,10,15], x = 1 |
示例 3:
1 | 输入:nums = [1,2,3,4], x = 3 |
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
0 <= x < nums.length
思路
1.一开始想到的就是双指针,不过是暴力的双指针,想法就是从头指针i=0开始,尾指针从e = i + x开始,一个个遍历过去,计算每一个数字和当前头指针的数字的差的绝对值,然后记录一个min来获取到最小的那个绝对值。因为绝对值是大于等于0的,一旦遍历的时候,min等于0了,就直接返回,不用继续往下遍历了。不过这个方法的时间复杂度是o(n^2),计算出来超时了,比赛的时候没有想到其他方法。
1 | public int minAbsoluteDifference(List<Integer> nums, int x) { |
2.后来看了别人的题解,自己调试了几次,才弄明白。
这里可以用TreeSet来维护当前值能够比较的元素,然后因为TreeSet内部使用红黑树实现的,查找的时候时间复杂度是o(logn),n个元素就是o(nlogn)。
下面在讲一下思路,首先TreeSet是用来维护当前元素能够匹配到的元素,也就是距离当前下标i至少有x距离的元素。因此for循环遍历的i是从x开始的,然后把当前元素左边距离i大于等于x的元素放到set中。
这里小伙伴可能有疑问,为什么不放右边的,只用放左边的?举个栗子,[5,3,2,10,15] , x = 1 , 我们是从i = 1, 数字3开始遍历的,先会左边把满足要求的5放到set,对于右边的2,10,15也是满足距离|i - j| > x,但是不用放,因为当我们i遍历到2的时候,2也会去找左边满足条件的元素,这个时候,2就会把3给放到set中,所以我们不需要处理右边的元素,只要每次把当前元素左边满足条件的元素给放到set中就可以了。
然后我们在调用TreeSet的函数ceiling(),floor()找到比当前元素大和小的元素,找到它们中和当前元素nums[i]差值的绝对值的最小值就可以了。整个数组遍历完,就找到了最小值。
时间复杂度:o(nlogn)
空间复杂度:o(n)
1 | public int minAbsoluteDifference(List<Integer> nums, int x) { |