zoukankan      html  css  js  c++  java
  • 分治-求逆序数

    在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,
    那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
    比如: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()
     
  • 相关阅读:
    类的高内聚低耦合
    面向对象是三个特征:封装、继承、多态
    抽象类和接口
    remoting和webservice
    装箱和拆箱
    数据库
    遍历TextBox控件
    索引类型
    .NET和C#有什么区别
    三层架构
  • 原文地址:https://www.cnblogs.com/an-wl/p/12804012.html
Copyright © 2011-2022 走看看