493. Reverse Pairs

参考:https://www.jianshu.com/p/b661d3e802f9

数组类问题两种思路:
思路一: T ( i , j ) = T ( i , j − 1 ) + C T(i,j) = T(i,j-1)+C T(i,j)=T(i,j1)+C
思路二: T ( i , j ) = T ( i , m ) + T ( m , j ) + C T(i,j) = T(i,m)+T(m,j)+C T(i,j)=T(i,m)+T(m,j)+C

解法一:BST

使用思路一,每次统计[0,j-1]中大于2*a[j]的元素个数
Naive方法 O ( n 2 ) O(n^2) O(n2)
使用BST,不过要写平衡树,有点麻烦

解法二:BIT-树状数组

使用的也是思路一,首先复制一个排序的数组 B = [ b 1 , . . . , b n ] B=[b_1,...,b_n] B=[b1,...,bn],从大到小排
树状数组中的 A [ i ] A[i] A[i]对应的是元素 b i b_i bi是否已出现
那么C[i]对应的是大于等于i的元素出现了多少个
当遍历到原始数组的第j个元素时,序号比它小的元素都出现过了
假如maxi是大于2*nums[j]的最大元素【这可以用二分查找找】
那么明显与nums[j]相关的逆序对数为 C [ m a x i ] C[maxi] C[maxi]

可见,树状数组在统计【小于/大于某个值的元素的和】上有妙用

两个坑:
  1. 使用的时候注意树状数组原始数组A的下标是从1开始的
  2. 二分查找的时候需要注意整个数组都小于要查找的数的情况
class Solution(object):
    def reversePairs(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        import copy
        A = list(sorted(copy.deepcopy(nums),reverse=True))
        n = len(A)
        c = [0]*n
        ans = 0
        def lowbit(k):
            return -k&k

        def add(k, d): # k>=1
            while k<=n:
                c[k - 1] += d
                k += lowbit(k)

        def sum(k): # k>=1
            res = 0
            while k>=1:
                res += c[k-1]
                k -= lowbit(k)
            return res

        def bs(ele):
            l = 0
            r = n
            while r-l>1:
                mid = (r+l)>>1
                if A[mid]>=ele:
                    l = mid
                else:
                    r = mid
            if A[l]>=ele:
                return l
            else:
                return -1

        for ele in nums:
            index = bs(2*ele+1)
            if index!= -1:
                ans += sum(index+1)
            add(bs(ele)+1, 1)

        return ans

解法三:归并排序

归并是思路二,注意检查逆序对的时机
整个循环里用一个统一的指针,这样不需要每次都检查
要么在每放一个nums[i]时对nums[j]检查(加的值与j无关),要么在每放一个nums[j]时对nums[i]检查(加的值与i无法)
归并排序版:

class Solution(object):
    def merge(self, l, r):
        if r-l<=1:
            return
        mid = (r+l)>>1
        self.merge(l,mid)
        self.merge(mid, r)
        c = []
        i=l
        j=mid
        pointer_j = mid
        while i<mid:
            while pointer_j<r and self.nums[pointer_j]*2<self.nums[i]:
                pointer_j += 1
            self.ans += pointer_j-mid
            while j<r and self.nums[i]>self.nums[j]:
                c.append(self.nums[j])
                j += 1
            c.append(self.nums[i])
            i += 1
        while j < r:
            c.append(self.nums[j])
            j += 1
        self.nums = self.nums[:l]+c+self.nums[r:]


    def reversePairs(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        self.nums = nums
        self.ans = 0
        self.merge(0,len(nums))
        return self.ans

实际在leetcode里跑的时候自己排序好像会超时= =,可能是临时数组的操作太浪费时间了,还不如让python排序

class Solution(object):
    def merge(self, lis):
        if len(lis)<=1:
            return lis
        mid = len(lis)>>1
        a = self.merge(lis[0:mid])
        b = self.merge(lis[mid:len(lis)])
        r = len(b)
        ptr = 0
        for ele in a:
            while ptr < r and ele > 2 * b[ptr]:
                ptr += 1
            self.ans += ptr
        lis.sort()
        return lis

    def reversePairs(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        self.nums = nums
        self.ans = 0
        self.merge(nums)
        return self.ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值