演算法第十一題(攻克歸併排序)

2021-10-07 09:30:12 字數 4355 閱讀 2964

陣列中的逆序對

class

solution

:def

reversepairs

(self, nums: list[

int])-

>

int:

self.cnt =

0def

merge

(nums, start, mid, end, temp)

: i, j = start, mid +

1while i <= mid and j <= end:

if nums[i]

<= nums[j]:)

i +=

1else

: self.cnt += mid - i +1)

j +=

1while i <= mid:

) i +=

1while j <= end:

) j +=

1for i in

range

(len

(temp)):

nums[start + i]

= temp[i]

temp.clear(

)def

mergesort

(nums, start, end, temp)

:if start >= end:

return

mid =

(start + end)//2

mergesort(nums, start, mid, temp)

mergesort(nums, mid +

1, end, temp)

merge(nums, start, mid, end, temp)

mergesort(nums,0,

len(nums)-1

,)return self.cnt

歸併排序的關鍵是並,並的過程中對兩個有序陣列進行合併,合併的過程中能夠計算逆序對的個數。

計算右側小於當前元素的個數

class

solution

:def

countsmaller

(self, nums)

: size =

len(nums)

if size ==0:

return

if size ==1:

return[0

] temp =

[none

for _ in

range

(size)

] indexes =

[i for i in

range

(size)

] res =[0

for _ in

range

(size)

] self.__helper(nums,

0, size -

1, temp, indexes, res)

return res

def__helper

(self, nums, left, right, temp, indexes, res)

:if left == right:

return

mid = left +

(right - left)//2

# 計算一下左邊

self.__helper(nums, left, mid, temp, indexes, res)

# 計算一下右邊

self.__helper(nums, mid +

1, right, temp, indexes, res)

if nums[indexes[mid]

]<= nums[indexes[mid +1]

]:return

self.__sort_and_count_smaller(nums, left, mid, right, temp, indexes, res)

def__sort_and_count_smaller

(self, nums, left, mid, right, temp, indexes, res)

:# [left,mid] 前有序陣列

# [mid+1,right] 後有序陣列

# 先拷貝,再合併

for i in

range

(left, right +1)

: temp[i]

= indexes[i]

l = left

r = mid +

1for i in

range

(left, right +1)

:if l > mid:

# l 用完,就拼命使用 r

# [1,2,3,4] [5,6,7,8]

indexes[i]

= temp[r]

r +=

1elif r > right:

# r 用完,就拼命使用 l

# [6,7,8,9] [1,2,3,4]

indexes[i]

= temp[l]

l +=

1# 注意:此時前面剩下的數,比後面所有的數都大

res[indexes[i]]+=

(right - mid)

elif nums[temp[l]

]<= nums[temp[r]]:

# [3,5,7,9] [4,6,8,10]

indexes[i]

= temp[l]

l +=

1# 注意:

res[indexes[i]]+=

(r - mid -1)

else

:assert nums[temp[l]

]> nums[temp[r]

]# 上面兩種情況只在其中一種統計就可以了

# [3,5,7,9] [4,6,8,10]

indexes[i]

= temp[r]

r +=

1

同樣是算個數,但是精確到了每個元素的個體,這樣需要索引陣列來記錄每次排序完的元素順序。

class

solution

:def

countsmaller

(self, nums):if

not nums:

return

counts =[0

] sorts =

[nums[-1

]]for i in

range

(len

(nums)-2

,-1,

-1):

ele = nums[i]

l =0 r =

len(sorts)

while l < r:

mid =

(l + r)//2

if sorts[mid]

>= ele:

r = mid

else

: l = mid +

1 index = l

sorts.insert(index,ele)

return counts[::

-1]

更巧妙的方法:開闢乙個陣列,從後往前讀取元素,並使用二分查詢,找出陣列的下限,即小於當前元素的個數。

複習:二分查詢無重複元素版:

mid = (left + right) // 2

其實要邏輯弄清楚:

這裡的right = len(nums) - 1

while left <= right:

mid < element : left = mid + 1

mid > element : right = mid - 1

mid == element : return mid

return -1

二分查詢 上限與下限:

下限:這裡的right = len(nums)

while left < right:

mid >= element: right = mid

mid < element: left = mid + 1

return left

上限:while left < right:

mid <= element: left = mid + 1

mid > element : right = mid

return left

2018暑假第十一題

題目 給定 n 個非負整數 a1,a2,an,每個數代表座標中的乙個點 i,ai 在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 i,ai 和 i,0 找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。python 說明 你不能傾斜容器,且 n 的值至少為 2。圖中垂直線代...

歸併演算法 歸併排序

歸併演算法 歸併排序 這周需要用到歸併演算法,於是找了找相關的資料,整理如下 歸併排序 merge sort 是利用 歸併 技術來進行排序。歸併是指將若干個已排序的子檔案合併成乙個有序的檔案。兩路歸併演算法 1 演算法基本思路 設兩個有序的子檔案 相當於輸入堆 放在同一向量中相鄰的位置上 r low...

第十一章 外部排序

第十一章 外部排序 第十一章外部排序 一 內容提要 1 外部排序指待排序檔案較大,記憶體一次存放不下,尚需存放在外部介質的檔案的排序。2 為減少平衡歸併中外存讀寫次數所採取的方法 增大歸併路數和減少歸併段個數。3 利用敗者樹增大歸併路數。4 利用置換 選擇排序增大歸併段長度來減少歸併段個數。5 由長...