【日更刷题】1534. 统计好三元组

119 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

一、题目描述:

1534. 统计好三元组 - 力扣(LeetCode)

给你一个整数数组 arr ,以及 a、b 、c 三个整数。请你统计其中好三元组的数量。

如果三元组 (arr[i], arr[j], arr[k]) 满足下列全部条件,则认为它是一个 好三元组 。

  • 0 <= i < j < k < arr.length
  • |arr[i] - arr[j]| <= a
  • |arr[j] - arr[k]| <= b
  • |arr[i] - arr[k]| <= c

其中 |x| 表示 x 的绝对值。

返回 好三元组的数量

 

示例 1:

输入:arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3
输出:4
解释:一共有 4 个好三元组:[(3,0,1), (3,0,1), (3,1,1), (0,1,1)]

示例 2:

输入:arr = [1,1,2,2,3], a = 0, b = 0, c = 1
输出:0
解释:不存在满足所有条件的三元组。

提示:

  • 3 <= arr.length <= 100
  • 0 <= arr[i] <= 1000
  • 0 <= a, b, c <= 1000

二、思路分析:

暴力法 没啥好说的

太简单了,完全没啥好说的,时间复杂度大概在O(n^3)O(n3)。

看了看题解区没找到精巧的解法,学习了提交记录排行中速度排前几名的思路。

j和k的遍历是无法避免的,而当这两者确定后,i的选择有些许搞头

如果提前将每个位置之前所有位置的数进行排序,那么arr[j]和arr[k]都确定后

根据a和c算出上下界后,可以通过二分查找从已排序的数列内确定满足要求的arr[i]

排序的时间复杂度O(klogk)O(k\log k),对n个位置遍历显然低于O(n3)O(n^3),二分查找O(logk)O(\log k)

也低于原有的k次判断,所以时间效率上有提升

但是当数组很长时,第一步存的排序结果会占用大量空间。

三、AC 代码:

from bisect import bisect_left, bisect_right

class Solution:
    def countGoodTriplets(self, arr: List[int], a: int, b: int, c: int) -> int:
        res = 0
        sorti = [sorted(arr[:i]) for i in range(len(arr))]
        for k in range(2, len(arr)):
            ak = arr[k]
            for j in range(1, k):
                aj = arr[j]
                if abs(ak - aj) > b:
                    continue
                prevj = sorti[j]
                L, R = max(aj - a, ak - c), min(aj + a, ak + c)
                if L > R:
                    continue
                iL = bisect.bisect_left(prevj, L)
                iR = bisect.bisect_right(prevj, R, iL)
                res += iR-iL
                
        return res   

四、总结:

一次典型的优化提速:空间换时间