歸併排序,合併有序陣列,逆序對個數

2022-05-07 17:54:10 字數 2024 閱讀 4523

之所以將標題中三者放一起是因為它們有密不可分的關係.

定義乙個空列表 li 用來存放排序後的值;

定義兩個 cursor lc 和 rc,分別指向左右列表的首部;

比較 lc 和 rc 指向的值,將較小的值放入 li,同時將指向較小值得游標右移一位;

迴圈上一步,直到某個游標指向最後;這時左右列表其中乙個的全部值已經被加入到 li 中;

將另外乙個列表中的剩餘值加入到 li 中.

def merge_ordered_list(left, right):

res =

lc = rc = 0

while lc < len(left) and rc < len(right):

if left[lc] <= right[rc]:

lc += 1

else:

rc += 1

res.extend(left[lc:])

res.extend(right[rc:])

return res

由以上**段可以看出,合併過程中只對左右列表分別進行了一遍歷,因此時間複雜度為o(n)

歸併排序分為兩步:

將資料盡量平均分為左右兩部分;

對左右兩部分分別進行排序(遞迴呼叫);

將左右兩部分合併,見上節merge_ordered_list.

def merge_sort(li):

if len(li) == 1:

return li

# split

mid_index = len(li) // 2

left = merge_sort(li[:mid_index])

right = merge_sort(li[mid_index:])

# merge

return merge_ordered_list(left, right)

因為每次都是平均分的,因此將乙個長度為 n 的列表分為 n 個長度為 1 的子列表需要lg(n)次操作(可以將拆分過程想象為樹的分叉),因此merge_sort需遞迴呼叫 n 次;

又因為每次呼叫的時間複雜度為o(n),故整個過程的時間複雜度為o(nlg(n))

如果採用暴力求解,分別求每個元素逆序對,需要兩兩比較列列表中的元素,時間複雜度為o(n**2);

結合歸併排序可以將時間複雜度降為o(nlg(n));

在第一節合併有序列表第三步中,rc 指向元素right[rc]小於 lc 指向元素left[lc]時,left[lc:]中的每個元素都和right[rc]組成了逆序對,由此可得出逆序對個數,**如下:

merge_ordered_list進行稍許修改,記錄逆序對個數.

inversion_count = 0

def merge_ordered_list(left, right):

global inversion_count

res =

lc = rc = 0

while lc < len(left) and rc < len(right):

if left[lc] <= right[rc]:

lc += 1

else:

rc += 1

# 統計逆序對個數

inversion_count += len(left[lc:])

res.extend(left[lc:])

res.extend(right[rc:])

return res

這時呼叫merge_sort會同時得出li中逆序對個數,時間複雜度為歸併排序的複雜度o(nlg(n)).

合併有序陣列

時限 1000ms 記憶體限制 10000k 總時限 3000ms 描述 給你兩個有序且公升序的陣列,請你把它們合成乙個公升序陣列並輸出 give you two ordered ascending array,you put them into one ascending array and ou...

合併有序陣列

描述 給你兩個有序整數陣列 nums1 和 nums2,請你將 nums2 合併到 nums1 中,使 num1 成為乙個有序陣列。說明 初始化 nums1 和 nums2 的元素數量分別為 m 和 n 你可以假設 nums1 有足夠的空間 空間大小大於或等於 m n 來儲存 nums2 中的元素。...

合併有序陣列

給你兩個有序整數陣列 nums1 和 nums2,請你將 nums2 合併到 nums1 中,使 nums1 成為乙個有序陣列。說明 初始化 nums1 和 nums2 的元素數量分別為 m 和 n 你可以假設 nums1 有足夠的空間 空間大小大於或等於 m n 來儲存 nums2 中的元素。vo...