分治-求逆序数

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,
那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
比如:74386,逆序为:74,73,76,43,86,所以逆序数为:5
1.直接计数法虽然简单直观,但是其时间复杂度是 O(n^2),如果数据量很大,程序会崩溃

2.一个更快(但稍复杂)的计算方法是在归并排序的同时计算逆序数,该算法耗时最小。
思路:假设需要求74386的逆序数,利用分治的思想,先左半边743的逆序数a,然后再求86的
逆序数b,最后再求左右各取一个数所构成的逆序数c,最后总的逆序数为:a+b+c
这里提醒一下,其实求743的逆序数a的过程,其实也经历了前面3个步骤,即先求左,再求右,
最后再左右各取1个数,最后的求和整个过程。
这样就可以利用递归的思想来解决这样的问题,边排序,边统计逆序数。

着重解释一下根据左右各取一个元素求逆序数的思路。864 | 73
左右都是从大到小排序好了,如果8,变量i >7,变量j,那么7之后的数都满足逆序数,
接下来i+1移动到6,6<7,不满足逆序数,j+1移动到3,6>3,那么3之后的数都满足逆序数,
通过这样的循环遍历
从而求到逆序数的值。

Python代码实现:
 1 import random
 2 import time
 3 
 4 
 5 def mergeSortAndCount(l,start,end):
 6     if (start>=end):
 7         return 0
 8     mid = (start+end)//2
 9     # 左边从大到小的排序,排序的同时,计算逆序数的值
10     leftCount = mergeSortAndCount(l,start,mid)
11     # 右边从大到小的排序,排序的同时,计算逆序数的值
12     rightCount = mergeSortAndCount(l,mid+1,end)
13     # i左边列表的游标,j游标列表的游标,count逆序数的计数变量
14     i,j,count = start,mid+1,0
15 
16     while i <= mid and j <= end :
17         if l[i] > l[j]:
18             count += end - j + 1
19             i += 1
20         else:
21             # l[i],l[j] = l[j],l[i]
22             j += 1
23     # 先用tempList存储从大到小排序,最后在根据位置替换原list
24     i, j = start, mid + 1
25     tempList = []
26     while i <= mid and j <= end:
27         if l[i] > l[j]:
28             tempList.append(l[i])
29             i += 1
30         else:
31             # l[i],l[j] = l[j],l[i]
32             tempList.append(l[j])
33             j += 1
34     #如果还剩余的元素,则把它补充进tempList列表
35     if i <= mid:
36         tempList.extend(l[i:mid+1])
37     if j <= end:
38         tempList.extend(l[j:end+1])
39     l[start:end+1] = tempList
40 
41     return leftCount + rightCount + count
42 
43 def main():
44     numstr = input("请输入一段数值:")
45     numList = []
46     for i in numstr:
47         numList.append(int(i))
48     #n = 1000
49     #numList = list(range(1,n))
50     #random.shuffle(numList)
51     #print(numList)
52     begin_time = time.perf_counter()
53     rtn = mergeSortAndCount(numList,0,len(numList)-1)
54     end_time = time.perf_counter()
55     print("逆序数个数:%d"%rtn)
56     print("共耗时:%f"%(end_time-begin_time))
57     print(numList)
58 
59 if __name__ == "__main__":
60     main()

 

 
posted @ 2020-04-29 18:51  StudyNLP  阅读(683)  评论(0编辑  收藏  举报