【剑指offer】数组中的逆序对(校正书上错误)【归并排序】

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

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

数据范围:

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

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

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

算法思路

归并排序可以用来寻找逆序对,时间复杂度为O(logN)
在这里插入图片描述


书中代码的错误:

按照书上的算法,可以写出如下代码:

class Solution:
    def RecursionCount(self, data, copy, start, end):
        print(start, end, data, copy)
        if start >= end:
            copy[start] = data[start]
            return 0
        count = 0
        length = int((end - start) / 2)
        leftCount = self.RecursionCount(data, copy, start, start + length)
        rightCount = self.RecursionCount(data, copy, start + length + 1, end)
        #data = copy[:]  #排序好之后,data要拷贝copy,才能保证data两边是排好序的。
        i, j = start + length, end
        copyIndex = end
        while i >= start and j >= start + length + 1:
            if data[i] > data[j]:
                copy[copyIndex] = data[i]
                copyIndex -= 1
                i -= 1
                count += (j - start - length)
            else:
                copy[copyIndex] = data[j]
                copyIndex -= 1
                j -= 1
        #比较之后,可能有一边没遍历完,copy可能没被全部填满,需要继续填充copy
        while i >= start:
            copy[copyIndex] = data[i]
            copyIndex -= 1
            i -= 1
        while j >= start + length + 1:
            copy[copyIndex] = data[j]
            copyIndex -= 1
            j -= 1
        #data[start:end+1] = copy[start:end+1]
        print(start, end, data, copy)
        return leftCount + rightCount + count
    def InversePairs(self, data):
        # write code here
        if data == []:
            return 0
        copy = data[:]
        #copy = [0] * len(data)
        return self.RecursionCount(data, copy, 0, len(data) - 1)
data = [7,5,6,4]
print(Solution().InversePairs(data))

输出:

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

从输出可以看到,并没有输出正确的结果,也没有排序,原因是data数组并没排序好,copy数组是根据data数组排序的,但是data数组并没有在递归结束前有序。比如[7, 5, 6, 4] [5, 7, 4, 6],5比4大的时候,将5作为copy的最后一个元素。最后输出[6, 4, 7, 5]。


正确的解法(超时)

class Solution:
    def RecursionCount(self, data, copy, start, end):
        print(start, end, data, copy)
        if start >= end:
            copy[start] = data[start]
            return 0
        count = 0
        length = int((end - start) / 2)
        leftCount = self.RecursionCount(data, copy, start, start + length)
        rightCount = self.RecursionCount(data, copy, start + length + 1, end)
        data = copy[:]  #排序好之后,data要拷贝copy,才能保证data两边是排好序的。
        i, j = start + length, end
        copyIndex = end
        while i >= start and j >= start + length + 1:
            if data[i] > data[j]:
                copy[copyIndex] = data[i]
                copyIndex -= 1
                i -= 1
                count += (j - start - length)
            else:
                copy[copyIndex] = data[j]
                copyIndex -= 1
                j -= 1
        #比较之后,可能有一边没遍历完,copy可能没被全部填满,需要继续填充copy
        while i >= start:
            copy[copyIndex] = data[i]
            copyIndex -= 1
            i -= 1
        while j >= start + length + 1:
            copy[copyIndex] = data[j]
            copyIndex -= 1
            j -= 1
        #data[start:end+1] = copy[start:end+1]
        print(start, end, data, copy)
        return leftCount + rightCount + count
    def InversePairs(self, data):
        # write code here
        if data == []:
            return 0
        copy = data[:]
        #copy = [0] * len(data)
        return (self.RecursionCount(data, copy, 0, len(data) - 1) % 1000000007)

但是这种解法会超时,造成时间复杂度过高,有两个原因:

  1. copy初始化没有必要完全拷贝data,可以随便初始化
  2. 归并排序采用分治法,data与copy同步同样在递归的过程中,采用分治法的思想拷贝

通过的代码

class Solution:
    def RecursionCount(self, data, copy, start, end):
        #print(start, end, data, copy)
        if start >= end:
            copy[start] = data[start]
            return 0
        count = 0
        length = int((end - start) / 2)
        leftCount = self.RecursionCount(data, copy, start, start + length)
        rightCount = self.RecursionCount(data, copy, start + length + 1, end)
        #data = copy[:]  #排序好之后,data要拷贝copy,才能保证data两边是排好序的。
        i, j = start + length, end
        copyIndex = end
        while i >= start and j >= start + length + 1:
            if data[i] > data[j]:
                copy[copyIndex] = data[i]
                copyIndex -= 1
                i -= 1
                count += (j - start - length)
            else:
                copy[copyIndex] = data[j]
                copyIndex -= 1
                j -= 1
        #比较之后,可能有一边没遍历完,copy可能没被全部填满,需要继续填充copy
        while i >= start:
            copy[copyIndex] = data[i]
            copyIndex -= 1
            i -= 1
        while j >= start + length + 1:
            copy[copyIndex] = data[j]
            copyIndex -= 1
            j -= 1
        data[start:end+1] = copy[start:end+1]
        #print(start, end, data, copy)
        return leftCount + rightCount + count
    def InversePairs(self, data):
        # write code here
        if data == []:
            return 0
        #copy = data[:]
        copy = [0] * len(data)
        return (self.RecursionCount(data, copy, 0, len(data) - 1) % 1000000007)
data = [7,5,6,4]
print(Solution().InversePairs(data))

输出中间结果可以看到,将data数组使用了归并排序算法进行了排序:

0 3 [7, 5, 6, 4] [0, 0, 0, 0]
0 1 [7, 5, 6, 4] [0, 0, 0, 0]
0 0 [7, 5, 6, 4] [0, 0, 0, 0]
1 1 [7, 5, 6, 4] [7, 0, 0, 0]
0 1 [5, 7, 6, 4] [5, 7, 0, 0]
2 3 [5, 7, 6, 4] [5, 7, 0, 0]
2 2 [5, 7, 6, 4] [5, 7, 0, 0]
3 3 [5, 7, 6, 4] [5, 7, 6, 0]
2 3 [5, 7, 4, 6] [5, 7, 4, 6]
0 3 [4, 5, 6, 7] [4, 5, 6, 7]
5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值