【分治】逆序?qū)τ嬎?Count Inversion

逆序?qū)Χx

如果存在正整數(shù)i,j使得1\leq i<j\leq n陷遮,而且A[i]>A[j],則<A[i],A[j]>這個有序?qū)ΨQ為A的一個逆序?qū)呀卜Q作逆序數(shù)拷呆。

例題1 - LeetCode劍指 Offer 51. 數(shù)組中的逆序?qū)?/h1>

題目

在數(shù)組中的兩個數(shù)字,如果前面一個數(shù)字大于后面的數(shù)字,則這兩個數(shù)字組成一個逆序?qū)Σ绺]斎胍粋€數(shù)組腰懂,求出這個數(shù)組中的逆序?qū)Φ目倲?shù)。

輸入: [7,5,6,4]
輸出: 5
限制:0 <= 數(shù)組長度 <= 50000
思路

逆序?qū)Γ?lt;7,5>,<7,6>,<7,4>,<5,4>,<6,4>

1. 暴力枚舉

數(shù)組中每個元素A[i]與其后面每個元素A[j](j>i)進(jìn)行比較项秉,若A[i]>A[j]則逆序?qū)?shù)量加1绣溜。
時間復(fù)雜度:O(n^2)

2. 分治

若數(shù)組元素個數(shù)為0或1,則該數(shù)組逆序?qū)?shù)量為0娄蔼;若數(shù)組元素為有序怖喻,則該數(shù)組逆序?qū)?shù)量為0∷晁撸可以發(fā)現(xiàn)锚沸,逆序?qū)?shù)量其實就是將無序數(shù)組排為有序后,數(shù)組元素交換的次數(shù)涕癣。

使用分治算法哗蜈,遞歸將數(shù)組進(jìn)行二分(low ~ middle 和 middle+1 ~ high),直至為僅剩1個元素坠韩。此時逆序?qū)?shù)量為0距潘。再將數(shù)組(low ~ middle 和 middle+1 ~ high)兩兩依次合并,合并時若左半部分?jǐn)?shù)組中的元素A[i],(low\leq i\leq mid)只搁,則逆序?qū)?shù)量增加mid-i+1
以題目為例:[7, 5, 6 ,4 ]

逆序?qū)?jpg

時間復(fù)雜度:O(nlog n)

具體代碼:

#include <bits/stdc++.h>
using namespace std;
vector<int> tmp;
long long int sum = 0;
long long int merge(vector<int> &nums,int low,int mid,int high){
    for (int i=low;i<=high;i++)
        tmp[i] = nums[i];
    int i = low;
    int j = mid+1;
    int k = low;
    while (i<=mid && j<=high){
        if (tmp[i]<=tmp[j])
            nums[k++] = tmp[i++];
        else {
            nums[k++] = tmp[j++];   
            sum += (mid-i+1);   
        }
    }
    while(i<=mid)
        nums[k++] = tmp[i++];
    while(j<=high)
        nums[k++] = tmp[j++];   
    return sum;
}

long long int mergeSort(vector<int> &nums,int low,int high){
    if (low == high)
        return 0;
    int mid=low+(high-low)/2;
    mergeSort(nums,low,mid);
    mergeSort(nums,mid+1,high);
    return merge(nums,low,mid,high);
}

int main(){
    int n,num;
    vector<int> nums;
    scanf("%d",&n);
    for (int i=0;i<n;i++){
        scanf("%d",&num);
        nums.push_back(num);
    }
    if (nums.size() < 2){
        cout << sum << endl;
        return 0;
    }
    tmp.resize(nums.size(),0);
    printf("%lld",mergeSort(nums,0,nums.size()-1));
    return 0;
}



例題2 - Count Inversion

Problem Description

Recall the problem of finding the number of inversions. As in the course, we are given a sequence of n numbers a_1,a_2,...a_n and we define an inversion to be a pair i<j such that a_i>a_j
We motivated the problem of counting inversions as a good measure of how different two orderings are. However, one might feel that this measure is too sensitive. Let's call a pair a significant inversion if i<j and a_i>3a_j. Give an O(nlog n)algorithm to count the number of significant inversions between two orderings.
The array contains N elements (1 \leq N \leq 100,000). All elements are in the range from 1 to 1,000,000,000.

Input

The first line contains one integer N , indicating the size of the array. The second line contains N elements in the array.
· 50% test cases guarantee that N<100

Output

Output a single integer which is the number of pairs of significant inversions.

Sample Inout

6
13 8 5 3 2 1

Sample Output

6

題意與例題1相同音比,只不過增加一個限定條件:a_i>3a_j,但此時使用分治算法后氢惋,將數(shù)組(low~middle 和 middle+1~high)兩兩依次合并時洞翩,合并時若左半部分?jǐn)?shù)組中的元素A[i],(low \leq i \leq mid)大于右半部分?jǐn)?shù)組元素A[j],(mid+1 \leq j \leq high),且A[pos]>3*A[j],(i \leq pos \leq mid) 則逆序?qū)?shù)量增加mid-pos+1焰望。即骚亿,不能僅僅通過比較A[i],A[j]就增加逆序?qū)?shù)量,如進(jìn)行[5,8,13][2,3]合并時柿估,雖然5<3*2但是5后面的元素還存在大于3*2的元素循未,所以此時需要遍歷左半部分?jǐn)?shù)組陷猫,直至出現(xiàn)第一個大于三倍A[j]的元素秫舌。因此需在原代碼基礎(chǔ)上進(jìn)行修改。
#include <bits/stdc++.h>
using namespace std;
vector<int> tmp;
long long int sum = 0;
long long int merge(vector<int> &nums,int low,int mid,int high){
    for (int i=low;i<=high;i++)
        tmp[i] = nums[i];
    int i = low;
    int j = mid+1;
    int k = low;
    while (i<=mid&&j<=high){
        if (tmp[i] <= tmp[j])
            nums[k++] = tmp[i++];
        else {
            int pos = i;
            while (pos <= mid){
                if (tmp[pos] > (long long)3*tmp[j]){//此處為了避免乘以3后超出范圍采用long long強(qiáng)制轉(zhuǎn)換绣檬。(OJ沒滿分就因為這足陨。)
                    sum += (mid-pos+1);
                    break;
                }
                pos++;
            }   
            nums[k++] = tmp[j++];   
        }
            
    }
    while(i<=mid)
        nums[k++] = tmp[i++];
    while(j<=high)
        nums[k++] = tmp[j++];   
    return con;
}

long long int mergeSort(vector<int> &nums,int low,int high){
    if (low == high)
        return 0;
    int mid = low+(high-low)/2;
    mergeSort(nums,low,mid);
    mergeSort(nums,mid+1,high);
    return merge(nums,low,mid,high);
}

int main(){
    int n,num;
    vector<int> nums;
    scanf("%d",&n);
    for (int i=0;i<n;i++){
        scanf("%d",&num);
        nums.push_back(num);
    }
    if (nums.size() < 2){
        cout << sum << endl;
        return 0;
    }
    tmp.resize(nums.size(),0);
    printf("%lld",mergeSort(nums,0,nums.size()-1));
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市娇未,隨后出現(xiàn)的幾起案子墨缘,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镊讼,死亡現(xiàn)場離奇詭異宽涌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蝶棋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門卸亮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玩裙,你說我怎么就攤上這事兼贸。” “怎么了吃溅?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵溶诞,是天一觀的道長。 經(jīng)常有香客問我决侈,道長螺垢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任颜及,我火速辦了婚禮甩苛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俏站。我一直安慰自己讯蒲,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布肄扎。 她就那樣靜靜地躺著墨林,像睡著了一般。 火紅的嫁衣襯著肌膚如雪犯祠。 梳的紋絲不亂的頭發(fā)上旭等,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音衡载,去河邊找鬼搔耕。 笑死,一個胖子當(dāng)著我的面吹牛痰娱,可吹牛的內(nèi)容都是我干的弃榨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼梨睁,長吁一口氣:“原來是場噩夢啊……” “哼鲸睛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坡贺,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤官辈,失蹤者是張志新(化名)和其女友劉穎箱舞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拳亿,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡晴股,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肺魁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片队魏。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖万搔,靈堂內(nèi)的尸體忽然破棺而出胡桨,到底是詐尸還是另有隱情,我是刑警寧澤瞬雹,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布昧谊,位于F島的核電站,受9級特大地震影響酗捌,放射性物質(zhì)發(fā)生泄漏呢诬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一胖缤、第九天 我趴在偏房一處隱蔽的房頂上張望尚镰。 院中可真熱鬧,春花似錦哪廓、人聲如沸狗唉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽分俯。三九已至,卻和暖如春哆料,著一層夾襖步出監(jiān)牢的瞬間缸剪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工东亦, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留杏节,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓典阵,卻偏偏與公主長得像奋渔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子萄喳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359