LeetCode 翻轉對(歸併排序)

2021-09-16 20:31:45 字數 2191 閱讀 6062

給定乙個陣列 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我們就將 (i, j) 稱作乙個重要翻轉對。

你需要返回給定陣列中的重要翻轉對的數量。

示例 1:

輸入: [1,3,2,3,1]

輸出: 2

示例 2:

輸入: [2,4,3,5,1]

輸出: 3

注意:

給定陣列的長度不會超過50000。

輸入陣列中的所有數字都在32位整數的表示範圍內。

思路分析:這道題雖然要求簡單,但是需要優化演算法,否則無法通過大量的測試資料。可能大家直接來暴搜,這種演算法肯定通不過。我們採取「歸併排序」策略。

首先我們需要了解,nums[ i ]的「翻轉對」 nums[ j ]只要它在j的後面就行,並不會影響nums[ i ]的「翻轉對」的計算。(比如在蠻力法中的兩層for迴圈)我們現在將採取「歸併排序」。

處理nums[left, right]

第一步:處理 [left, mid] (遞迴)

第二步:處理[mid + 1, right] (遞迴)

第三步:計算左段各個元素在右端構成的 「重要翻轉對」(由於排序左(右)段已經計算了左(右)段內產生的「重要翻轉對」,所以這裡只需要計算兩個段之間的「重要翻轉對」)

第四步:將兩段有序合併

class

solution

vector<

int>

mergevec

(nums.

size()

);sort(0

, nums.

size()

-1, nums, mergevec)

;//歸併排序

return result;

}//處理nums[left, right]

void

sort

(int left,

int right, vector<

int>

& data, vector<

int>

&mergevec)

int mid =

(left + right)/2

;sort

(left, mid, data, mergevec)

;//第一步:處理 [left, mid] (遞迴)

sort

(mid +

1, right, data, mergevec)

;//第二步:處理[mid + 1, right] (遞迴)

int i = left;

int j = mid +1;

//第三步:計算左段各個元素在右端構成的 「重要翻轉對」(由於排序左(右)段已經計算了左(右)段內產生的「重要翻轉對」,所以這裡只需要計算兩個段之間的「重要翻轉對」)

while

(j < right +

1&& i < mid +1)

else

}//第四步:有序合併左右兩段

merge

(left, right, data, mergevec)

;//data中[left, mid]和[mid + 1, right]兩段進行合併到result中[left, right]

//複製回data

for(

int i = left; i <= right; i++)}

//將data中[left, mid]和[mid + 1, right]兩段進行合併到result中[left, right]

void

merge

(int left,

int right, vector<

int>

& data, vector<

int>

&mergevec)

else

}//下面的迴圈只會執行乙個

LeetCode 493 翻轉對 歸併排序

如果 i j 分別屬於兩個有序區間,並且 nums i 2 nums j 則大於 i 的元素也都滿足需求,利用有序特點可以減少重複的比較操作。將兩個有序的陣列合併成乙個有序陣列稱為歸併。歸併排序包含了兩個過程 從上往下的分解 把當前區間一分為二,直至分解為若干個長度為1的子陣列 從下往上的合併 兩個...

leetcode493(翻轉對 歸併排序)

給定乙個陣列 nums 如果 i j 且 nums i 2 nums j 我們就將 i,j 稱作乙個重要翻轉對。你需要返回給定陣列中的重要翻轉對的數量。示例 1 輸入 1,3,2,3,1 輸出 2 示例 2 輸入 2,4,3,5,1 輸出 3 題解 一 歸併排序,在歸併排序的過程中,假設對於某歸併陣...

leetcode 歸併排序

首先對倆個有序陣列進行組合排序 def merge two vec nums1,nums2,res i 0 j 0 len i len nums1 len j len nums2 while i len i and j len j if nums1 i nums2 j i 1else j 1 res...