1814. Count Nice Pairs in an Array (数学方法巧解,警惕时间复杂度思维陷阱)

简介

题目链接 Leetcode 1814. Count Nice Pairs in an Array

一旦看透题目的本质,这道题非常的简单。但是由于题目规定输入列表的尺寸在10的5次方这个范围,如下:

1 <= nums.length <= 10^5
0 <= nums[i] <= 10^9

会使解题者下意识的认为这题应该用堆栈(Heap),二分法,树之类的数据结构,但其实最终这题就是一个简单的O(N)解法,非常意外。被误导的过程如下:

  • 看到输入尺寸 -> 推断合理的时间复杂度 -> 利用时间复杂度找符合的解法和数据结构

所以,警惕输入尺寸带来先入为主的时间复杂度上的误导。尽管以上过程可以在多数时候帮助解题,但是不要被这样的模式限制自己的思维

注意:文章中一切注解皆为Python代码

理解题目

题目非常简单。给定一个列表,找出所有符合以下条件的对(Pairs),返回总共的对数,条件如下:

  • 0 <= i < j < nums.length
  • nums[i] + rev(nums[j]) == nums[j] + rev(nums[i])

乍一看似乎只有O(N^2)的解法,甚至想不出O(NlogN)的解法,但其实简单的数学移项操作就能用O(N)完成这个问题。

把原公式,通过移项变成如下公式:

  • nums[i] - rev(nums[i]) == nums[j] - rev(nums[j])

因此,实现O(N)解法的步骤如下:

  • 我们需要用O(N)做一个新的列表,把其中每一个数字都反过来
  • 再对于每一个nums[i] - rev(nums[i])进行计数,这里可以用Python中的Counter或者单纯的dict
  • 接着对于每一个nums[i] - rev(nums[i])出现的频率,假定这个频率为freq,那么可以形成的对数为freq * (freq-1)
  • 最后返回对数总和即可

代码实现

class Solution:
    def countNicePairs(self, nums: List[int]) -> int:
        rev_nums = [int(str(num)[::-1]) for num in nums]
        c = collections.Counter([i-j for i, j in zip(nums, rev_nums)])
        return sum([freq * (freq-1) // 2 for _, freq in c.items() if freq > 1]) % int(1e9+7)

解题后的思考

经验固然重要,但不要被先入为主的经验限制了思考。

上一篇:LeetCode每日刷题-7. 整数反转


下一篇:使用Sklearn进行特征工程