題目描述分析:在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數p。並將p對1000000007取模的結果輸出。 即輸出p%1000000007
輸入描述:
題目保證輸入的陣列中沒有的相同的數字
資料範圍:
對於%50的資料,size<=10^4
對於%75的資料,size<=10^5
對於%100的資料,size<=2*10^5
示例1
輸入複製
1,2,3,4,5,6,7,0
輸出複製
7
求乙個陣列的逆序數有兩種比較高效的方法,數狀陣列和歸併排序
先講一下數狀陣列怎麼求解陣列的逆序數
解法1:樹狀陣列求解逆序數
樹狀陣列,顧名思義,就是採用陣列來模擬樹形結構唄,
那麼衍生出乙個問題?為什麼不直接建樹呢?答案是沒有必要,
因為樹狀陣列可以解決的問題沒有必要建樹,開銷太大了
樹狀陣列可以解決大部分基於區間上的更新以及區間上的求和問題
樹狀陣列因為是模擬樹的結構,其修改和查詢的時間複雜度都是o(log n)
黑色陣列代表原來的陣列(下面用a[i]代替),紅色結構代表我們的樹狀陣列(下面用c[i]代替),發現沒有,每個位置只有乙個方框,令每個位置存的就是子節點的值的和,則有比如我們要找前7項和,那麼應該是sum = c[7] + c[6] + c[4],這樣一來,我們就不需要遍歷a[1]到a[7]然後求和了,
只需要遍歷c[7],c[6],c[4],遍歷的元素數量大大減少了,效能得到了提公升
其實c陣列和a陣列是同乙個陣列,只是他們不同位置上的含義不同,比如c[5]代表a[5],c[6]代表a[5]+a[6]
說回逆序數,
怎麼用數狀陣列求逆序數呢?
求逆序數的巨集思路: 假設給定的序列為 4 3 2 1,我們從左往右依次將給定的序列輸入,每次輸入乙個數temp時,
就將當前序列中大於temp的元素的個數計算出來,並累加到ans中,最後ans就是這個序列的逆序數個數。
我們可以採用數狀陣列標記伴隨著輸入,該數字是否出現過,出現過則賦值1,
統計大於當前元素值的元素個數則可以通過當前總元素個數減去小於等於當前元素值的元素個數
採用數狀陣列求解逆序數的時間複雜度為:o(n*log n)
class解法2:歸併排序求解逆序數solution
void update(int x,int d)//
第x位置上的元素加上d
}int getsum(int x)//
求得小於等於x的和,因為元素的值為1,代表該元素出現過,也就是求得小於等於x的元素個數
return
res;
}int inversepairs(vectordata)
sum%=1000000007
;
return
sum;}};
歸併排序中先是劃分到底,直到需要並的兩個子陣列中只有乙個數字,
這兩個字序列就是分別有序的,然後兩個有序序列繼續合併,我們所做的處理就是在兩個有序序列合併的過程中進行計算即可
現在有兩個子串行,下標分別是[s,m],[m+1,t]
當前面子序列中某個元素i大於後面子序列中某個元素j時,元素i到m之間的元素肯定都是大於元素j的,因為陣列是有序的,
那麼他們和元素j都可以組成逆序對,所以我們需要知道此時i元素到m元素之間元素的數量,其數量可以表示為m-i+1,也可以表示為j-k,
k代表放入新陣列中已經有序的數字,這兩種表示方法都是同乙個意思
歸併排序求解逆序數的時間複雜度為:o(n*log n)
劍指offer 陣列中的逆序對
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。解法一 乙個數字能不能構成逆序對,關鍵看後面有幾個比他小的數字。根據這個思路,我們可以從後向前遍歷整個陣列。並用乙個大小為10的陣列,分別來儲存從後向前遍歷陣列時0 9每個數字...
劍指offer 陣列中的逆序對
題目描述 在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。class solution vector tmp len int res mergesort data,tmp,0,len 1 return res private...
劍指offer 陣列中的逆序對
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數。分析 類似於mergesort的思想,對於兩個排序的陣列,用兩個指標分別指向末尾,比如p,q,如果p的值大於q,那麼p與q和q之前所有數字都可以組成逆序對,count就加上後乙...