python逆序输出数字_求逆序对的个数(python实现)

剑指offer中的一道题,顺便安利一下上面的题可以在这个网址做在线测评,评判自己的方法到底有没有问题:https://www.nowcoder.com/ta/coding-interviews

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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

这道题首先想到可以用暴力求解,N^2的时间复杂度。

然后想到可以用分治的方法来求解,减少到O(NlogN)。

首先我这里写一个标准的分治法归并排序:

class MergeSortCal(object):

def merge_sort(self, arr, left, right):

if left >= right:

return

mid = int((left + right) / 2)

self.merge_sort(arr, left, mid)

self.merge_sort(arr, mid + 1, right)

self.merge(arr, left, mid, right)

pass

def merge(self, arr, left, mid, right):

l = left

r = mid + 1

start = left

res_arr = [0 for i in range(len(arr))]

while l <= mid and r <= right:

if arr[l] < arr[r]:

res_arr[start] = arr[l]

l += 1

start += 1

else:

res_arr[start] = arr[r]

r += 1

start += 1

while l <= mid:

res_arr[start] = arr[l]

l += 1

start += 1

while r <= right:

res_arr[start] = arr[r]

r += 1

start += 1

for i in range(left, right + 1):

arr[i] = res_arr[i]

if __name__ == '__main__':

arr = [int(x) for x in input().strip().split(',')]

sort_util = MergeSortCal()

sort_util.merge_sort(arr, 0, len(arr) - 1)

print(arr)

在完成了分治归并排序后,只需要做一点变化就可以在归并的同时统计逆序对的个数。

class MergeSortCal(object):

def merge_sort(self, arr, left, right, res):

if left >= right:

return res

mid = int((left + right) / 2)

res_left = self.merge_sort(arr, left, mid, res)

res_right = self.merge_sort(arr, mid + 1, right, res)

return self.merge(arr, left, mid, right, res_left + res_right)

def merge(self, arr, left, mid, right, res):

l = left

r = mid + 1

start = left

res_arr = [0 for i in range(len(arr))]

while l <= mid and r <= right:

if arr[l] < arr[r]:

res_arr[start] = arr[l]

l += 1

start += 1

else:

res_arr[start] = arr[r]

r += 1

start += 1

# 逆序

res += mid - l + 1

res = res % 1000000007

while l <= mid:

res_arr[start] = arr[l]

l += 1

start += 1

# 如果左边没走完

# self.res += right - (mid + 1) + 1

while r <= right:

res_arr[start] = arr[r]

r += 1

start += 1

for i in range(left, right + 1):

arr[i] = res_arr[i]

return res

if __name__ == '__main__':

# arr = [int(x) for x in input().strip().split(',')]

arr = [364, 637, 341, 406, 747, 995, 234, 971, 571, 219, 993, 407,

416, 366, 315, 301, 601, 650, 418, 355, 460, 505, 360, 965,

516, 648, 727, 667, 465, 849, 455, 181, 486, 149, 588, 233,

144, 174, 557, 67, 746, 550, 474, 162, 268, 142, 463, 221, 882,

576, 604, 739, 288, 569, 256, 936, 275, 401, 497, 82, 935, 983,

583, 523, 697, 478, 147, 795, 380, 973, 958, 115, 773, 870,

259, 655, 446, 863, 735, 784, 3, 671, 433, 630, 425, 930, 64,

266, 235, 187, 284, 665, 874, 80, 45, 848, 38, 811, 267, 575]

# arr = [1, 6, 3, 5]

sort_util = MergeSortCal()

result = sort_util.merge_sort(arr, 0, len(arr) - 1, 0)

print(arr)

print(result)

Post Views:

1,140

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值