数组中的逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

输入描述:

题目保证输入的数组中没有的相同的数字

数据范围:

对于%50的数据,size<=10^4

对于%75的数据,size<=10^5

对于%100的数据,size<=2*10^5

示例1

输入

复制

1,2,3,4,5,6,7,0

输出

复制

7

方法一:暴力

# -*- coding:utf-8 -*-
class Solution:
    def InversePairs(self, data):
        # write code here
        count=0
        n=len(data)
        for i in range(n-1):
            for j in range(1+i,n):
                if data[i]>data[j]:
                    count+=1
        return count

方法二:索引

import copy
def InversePairs(data):
    count = 0
    copys = copy.copy(data)
    # copys=data[:]
    # copys = copy.deepcopy(data)
    copys.sort()
    for i in range(len(copys)):
        count += data.index(copys[i])
        print('count=',count)
        data.remove(copys[i])
    return count
    # return count%1000000007
a=[1,2,3,5,6,7,4]
print(InversePairs(a))

方法三:归并

class Solution:
    def reversePairs(self, nums: List[int]) -> int:

        def f(L,R):
            if L>=R:
                return 0
            mid=(L+R)//2
            s=f(L,mid)+f(mid+1,R)
            i=L
            j=mid+1
            pos=L
            res=[]
            while i<=mid and j<=R:
                if nums[i]<=nums[j]:
                    # res.append(nums[i])
                    dp[pos]=nums[i]
                    i+=1
                else:
                    # res.append(nums[j])
                    dp[pos]=nums[j]
                    j+=1
                    s=s+(mid-i+1)
                pos+=1
            for k in range(i,mid+1):
                dp[pos]=nums[k]
                pos+=1
                # res.append(nums[i])
            for k in range(j,R+1):
                dp[pos]=nums[k]
                pos+=1
                # res.append(nums[i])
            nums[L:R+1]=dp[L:R+1]
            return s
        l=len(nums)
        dp=[0]*l
        return f(0,l-1)
class Solution:
    def InversePairs(self, data):
        # write code here
        # 思路:归并排序。分为两个部分,寻找两个部分内部的逆序列,再寻找两个部分之间交叉的逆序列。
        if not data:
            return 0
        # assist中存储的是排好序的列表,它也是下一次Merge时作为参考的列表,因此除了本次迭代内的片段,其他部分也要等于原始列表
        # 由于必须保证有两个列表,两个地址,因此不能直接用assist=data
        assist = [i for i in data]
        return self.Merge(data, assist, 0, len(data) - 1) % 1000000007

    # 每一个新的递归开始时,都是要大范围重新排序的,这个范围会覆盖所有以前递归过的片段,因此data和assist可以互换,因为上一次排好序的列表只在下一次的比较时需要使用,而不需要递延到下一次的辅助列表中。
    def Merge(self, data, assist, low, high):
        # 判断终止条件:如果子部分里面只剩下1个数,此时low=high,不用比较,返回0
        if low == high:
            assist[low] = data[low]  # 由于assist和data互换了,因此如果递归到最小单位,要按照上次算出的排序方式排序
            return 0
        mid = (low + high) / 2
        left = self.Merge(assist, data, low, mid)
        right = self.Merge(assist, data, mid + 1, high)
        # 开始归并排序
        count = 0
        i = mid
        j = high
        k = high  # k为assist列表的索引
        # 从后往前进行遍历,对左子列和右子列中的数进行比较大小
        while i >= low and j > mid:
            # 如果左子列最后一个数大于右子列最后一个数,表示左子列大于右子列所有的数
            if data[i] > data[j]:
                count += j - mid  # count要加上右子列中剩下元素的个数
                assist[k] = data[i]  # 将最大的数存入辅助列表
                i -= 1  # 最大数已被排序,将左子列向前遍历一个元素
            # 如果左子列最后一个数小于等于右子列最后一个数,不构成逆序对
            else:
                assist[k] = data[j]  # 将最大的数存入辅助列表
                j -= 1  # 最大数已被排序,将右子列向前遍历一个元素
            k -= 1
        # 上面一个while中还会剩下最后一个元素没有被排序,进入assist
        while i >= low:
            assist[k] = data[i]
            i -= 1
            k -= 1
        while j > mid:
            assist[k] = data[j]
            j -= 1
            k -= 1
        return left + right + count  # 返回当前左右子列计算出的逆序对数量,加上左右子列内部的逆序对数量

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值