def InversePairs(data):
# write code here
if not data:
return 0
copy = []
for i in data:
copy.append(i)
length = len(data)
count = InversePairsCore(data, copy, 0, length - 1)
print(count%1000000007)
return count%1000000007
def InversePairsCore(data, copy, start, end):
if start == end:
copy[start] = data[start]
return 0
length = int((end - start) / 2)
left = InversePairsCore(copy, data, start, start + length)
right = InversePairsCore(copy, data, start + length + 1, end)
i = start + length
j = end
index_copy = end
count = 0
while i >= start and j >= start + length + 1:
if data[i] > data[j]:
copy[index_copy] = data[i]
index_copy -= 1
i -= 1
count += j - start - length
else:
copy[index_copy] = data[j]
index_copy -= 1
j -= 1
copy += data[start:i+1]
copy += data[start + length + 1:j+1]
return (left + right + count)
data = [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]
InversePairs(data)
https://www.nowcoder.com/questionTerminal/96bd6684e04a44eb80e6a68efc0ec6c5
基本思想:
归并排序与之前的交换(快速)、选择(堆)等排序的思想不一样,“归并”的含义就是:
将两个或者两个以上的有序表组合成一个新的有序表,假定待排序表含有n个记录,则可以看做是n个有序的子表,每个子表的长度为1,然后两两归并,得到个长度为2或者为1的有序表;再两两归并,....如此重复,直到合并成一个长度为n的有序表为止,这种排序方法为2-路归并排序
初始关键字: 49 38 65 97 76 13 27
一趟归并后: 38 49 65 97 13 76 27
二趟归并后: 38 49 65 97 13 27 76
三趟归并后: 13 27 38 49 65 76 97
merge()的功能是将前后相邻的两个有序表归并成为一个有序表的算法。
设两段有序表A[low,...mid]、A[mid+1,...high]放在同一个有序表的两个位置上,先让它们复制到辅助数组B里面,每次从对应B中的两个段取出一个记录进行关键字的比较,先将小者放入A中,当数组B中有一段的下标超出其对应的表长时,即该段所有的元素已经完全复制到A中,另一端中的剩余部分直接复制到A中。
递归形式的2-路归并排序是基于分治的!过程如下:
- 分解:将含有n个元素的待排序表分成各含有n/2个元素的子表,采用二路归并算法对两个子表递归的地进行排序
- 合并:合并两个已排序的子表得到排序结果
代码如下:
# merge函数的功能是将前后相邻的两个有序子表归并成为一个有序表
# left和right就是两个前后相邻的有序子表,我们需要一个辅助数组result,最后返回的result就是最后的
# 归并排序结果
# i和j一起从0开始向后走,对应位置(不一定就是下标相同)谁小谁被收到result中去,然后下去的那个指针向
# 后走一个,直到最后
# 其实result += left[i:] 和 result += right[j:]只会执行一个,因为有一个已经被收光了。
def merge(left, right):
i, j = 0, 0
result = []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
# 递归形式的二路归并算法是基于分治的
# 分解:将n个记录一分为2,然后对分开的两个各含有n/2个元素的子表递归调用自身
# 合并: 合并两个已经排序的子表得到结果
def merge_sort(lists):
if len(lists) <= 1:
return lists
num = len(lists) /2
left = merge_sort(lists[:num])
right = merge_sort(lists[num:])
return merge(left, right)
性能:
- 空间:需要借助一个辅助数组B,所以空间复杂度为O(n)
- 时间:每一趟归并就是一个while循环,即O(n),一共要趟归并,所以算法时间复杂度是
稳定性:
merge不会改变相同关键字记录的相对次序,所以2路归并排序是一个稳定的排序算法。