国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C++算法 —— 分治(2)歸并

這篇具有很好參考價值的文章主要介紹了C++算法 —— 分治(2)歸并。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。


本篇前提條件是已學會歸并排序

1、排序數(shù)組

912. 排序數(shù)組

C++算法 —— 分治(2)歸并,C++算法,算法,c++,排序算法

排序數(shù)組也可以用歸并排序來做。

    vector<int> tmp;//寫成全局是因為如果在每一次小的排序中都創(chuàng)建一次,更消耗時間和空間,設置成全局的就更高效
    
    vector<int> sortArray(vector<int>& nums) {
        tmp.resize(nums.size());
        mergeSort(nums, 0, nums.size() - 1);
        return nums;
    }

    //歸并做法
    void mergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return ;
        int mid = (left + right) / 2;
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);
        int cur1 = left, cur2 = mid + 1, i = 0;
        while(cur1 <= mid && cur2 <= right)
        {
            tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
        }
        while(cur1 <= mid) tmp[i++] = nums[cur1++];
        while(cur2 <= right) tmp[i++] = nums[cur2++];
        for(int i = left; i <= right; i++)
        {
            nums[i] = tmp[i - left];
        }
    }

2、數(shù)組中的逆序對

劍指 Offer 51. 數(shù)組中的逆序對

C++算法 —— 分治(2)歸并,C++算法,算法,c++,排序算法

如果暴力枚舉,一定是可以解決問題的,但肯定不用這個解法。選擇逆序對,可以先把數(shù)組分成兩部分,左半部分 + 右半部分的逆序對,以及再找左半部分的數(shù)字和右半部分數(shù)字成對的數(shù),比如上面例子中,7和6,7和4就是這種情況。左 + 右 + 一左一右就是整體的逆序對數(shù)量。當這兩半部分都處理完后,就擴大區(qū)間,繼續(xù)上述操作。這個解法也就是利用歸并排序,歸并排序的思路就是劃分到最小的區(qū)間,只有1個數(shù),它一定是有序的,回到上一層,也就是2個數(shù)的區(qū)間,讓它們排好序,在它右邊的也是2個數(shù)的區(qū)間,重復和它一樣的操作,這樣兩個區(qū)間都有序后,再往上走一層,來到4個數(shù)的區(qū)間,4個數(shù),每一半都是有序的,將整體的4個數(shù)排成有序的,再往上走,來到8個數(shù)的區(qū)間,重復操作。

利用歸并排序的思路,我們在兩個區(qū)間都排成升序后,定義兩個指針cur指向兩個區(qū)間的開頭,然后一左一右比較大小,如果cur1比cur2大,那么cur1之后都比cur2大,就可以一次性加上多個逆序對的個數(shù)。

下面的代碼可以從最小的區(qū)間開始一個個代入來理解。從只有2個數(shù)的區(qū)間開始,走到遞歸處,分成2個只有1個數(shù)的區(qū)間,那就會返回0,兩處遞歸走完,來到下面的循環(huán),此時left是0,right是1,mid是0,帶入進去會發(fā)現(xiàn),最后的ret只會是0或者1,并且這2個數(shù)也在最后排好序了,返回后,來到上一層,也就是走左邊遞歸的那行代碼,然后再走右邊,也是2個數(shù),也是同樣的操作,2個區(qū)間排好序了,4個數(shù)的區(qū)間就一左一右比較大小,找出逆序對,排好序,再走到上一層,8個數(shù)的區(qū)間也是如此。

class Solution {
    int tmp[50010];
public:
    int reversePairs(vector<int>& nums) {
        return mergeSort(nums, 0, nums.size() - 1);
    }

    int mergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return 0;
        int ret = 0;
        //1. 找中間點,將數(shù)組分成兩部分
        int mid = (left + right) >> 1;
        // [left, mid] [mid + 1, right]
        //2. 左邊個數(shù) + 排序 + 右邊個數(shù) + 排序
        ret += mergeSort(nums, left, mid);
        ret += mergeSort(nums, mid + 1, right);
        //3. 一左一右的個數(shù)
        int cur1 = left, cur2 = mid + 1, i = 0;
        while(cur1 <= mid && cur2 <= right)//while體內(nèi)原本是歸并排序的代碼,現(xiàn)在就多加一點
        {
            if(nums[cur1] <= nums[cur2]) tmp[i++] = nums[cur1++];
            else
            {
                ret += mid - cur1 + 1;
                tmp[i++] = nums[cur2++];
            }
        }
        //4. 處理排序
        while(cur1 <= mid) tmp[i++] = nums[cur1++];
        while(cur2 <= right) tmp[i++] = nums[cur2++];
        for(int j = left; j <= right; j++)
        {
            nums[j] = tmp[j - left];//排序
        }
        return ret;
    }
};

3、計算右側小于當前元素的個數(shù)

315. 計算右側小于當前元素的個數(shù)

C++算法 —— 分治(2)歸并,C++算法,算法,c++,排序算法

此題和上一個題有相同之處,也是分治,也是利用歸并排序,這道題可以看作,當前元素后面,有多少比我小的,而上一題則是當前元素前面,有多少比我大的。仔細想一想,上一題是排升序,這一題排降序則更為合適。這題和上一題還有不同的地方。

cur1和cur2,排成降序,如果cur1 <= cur2,cur2++,因為我們要找比當前元素小的;如果cur1 > cur2,由于是降序,那么cur2之后的肯定都小,但這里不能加上ret,我們要返回一個數(shù)組,要把這個數(shù)加在當前元素的原始下標,因為數(shù)組已經(jīng)被我們給排序了,所以要找原始下標。這里的做法就是從最一開始就除了tmp外,再定義一個數(shù)組,存儲著原始下標,因為這時候還沒開始排序,可以找得到,然后每次原數(shù)組元素變換位置,這個下標數(shù)組也跟著變換。

我們要定義四個數(shù)組,一個是結果數(shù)組,一個是原始下標數(shù)組,一個是輔助數(shù)組,也就是tmp,記錄改動過的順序,一個是下標輔助數(shù)組,記錄改動后的下標順序。在while循環(huán)中,每次更新tmp,下標輔助數(shù)組也跟著更新。如果cur1大于cur2,那么除了更新,還需要往結果數(shù)組中寫入個數(shù),要在當前元素的原始下標處寫入個數(shù),這里最好要畫圖來理解,畫原始下標和下標變動后的圖。在最后for循環(huán)中的排序,除了原數(shù)組nums,還有原始下標數(shù)組也要排序。

    vector<int> index;//原始元素下標
    vector<int> res;//最終結果
    int tmp[500010];//排序輔助數(shù)組
    int tmpIndex[500010];//元素下標的輔助數(shù)組
public:
    vector<int> countSmaller(vector<int>& nums) {
        int sz = nums.size();
        index.resize(sz);
        res.resize(sz);
        for(int i = 0; i < sz; i++)
        {
            index[i] = i;
        }
        mergeSort(nums, 0, sz - 1);
        return res;
    }

    void mergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return ;
        int mid = (left + right) >> 1;
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);
        int cur1 = left, cur2 = mid + 1, i = 0;
        while(cur1 <= mid && cur2 <= right)
        {
            if(nums[cur1] <= nums[cur2])
            {
                tmp[i] = nums[cur2];
                tmpIndex[i++] = index[cur2++];
            }
            else 
            {
                res[index[cur1]] += right - cur2 + 1;//經(jīng)歷了之前的排序,index已經(jīng)記錄下了最新的下標變動,這里就可以直接用cur1來獲取正確的下標
                tmp[i] = nums[cur1];
                tmpIndex[i++] = index[cur1++];
            }
        }
        while(cur1 <= mid)
        {
            tmp[i] = nums[cur1];
            tmpIndex[i++] = index[cur1++];
        }
        while(cur2 <= right)
        {
            tmp[i] = nums[cur2];
            tmpIndex[i++] = index[cur2++];
        }
        for(int j = left; j <= right; j++)
        {
            nums[j] = tmp[j - left];
            index[j] = tmpIndex[j - left];
        }
    }

4、翻轉對

493. 翻轉對

C++算法 —— 分治(2)歸并,C++算法,算法,c++,排序算法

還是一樣的思路。左半部分,右半部分,然后一左一右。不過這里的條件不一樣。這里的解決辦法有兩個,一個是計算當前元素后面有多少元素的兩倍比我小,另一個是計算當前元素之前,有多少元素的一半比我大,這兩個的高效順序分別是降序和升序。

第一個思路,cur1和cur2,找當前元素的后面,那就以cur1為重點,如果cur2的2倍大于等于cur1,cur2就往后走,如果小于,那么后面的肯定都小于。第二個思路,cur1和cur2,找當前元素的前面,那就以cur2為重點,如果cur1的一半比cur2小,那么cur1后的肯定都符合條件,如果cur1的一半大于cur2,那cur1往后走。最后合并兩個有序數(shù)組。

    int tmp[50010];
public:
    int reversePairs(vector<int>& nums) {
        return mergeSort(nums, 0, nums.size() - 1);
    }

    int mergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return 0;
        int ret = 0;
        int mid = (left + right) >> 1;
        ret += mergeSort(nums, left, mid);
        ret += mergeSort(nums, mid + 1, right); 
        int cur1 = left, cur2 = mid + 1, i = left;//先計算翻轉對,0還是left都行
        /*while(cur1 <= mid)//這里排降序,也可以排升序
        {
            while(cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) cur2++;//2.0是為了防止除不盡
            if(cur2 > right) break;
            ret += right - cur2 + 1;
            cur1++;
        }*/
        while(cur2 <= right)//升序
        {
            while(cur1 <= mid && nums[cur2] >= nums[cur1] / 2.0) cur1++;
            if(cur1 > mid) break;
            ret += mid - cur1 + 1;
            cur2++;
        }
        cur1 = left, cur2 = mid + 1;//歸位一下,開始排序
        while(cur1 <= mid && cur2 <= right)
        {
            tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
            //tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur2++] : nums[cur1++];
        }
        while(cur1 <= mid) tmp[i++] = nums[cur1++];
        while(cur2 <= right) tmp[i++] = nums[cur2++];
        for(int j = left; j <= right; j++)
        {
            nums[j] = tmp[j];
        }
        return ret;
    }

結束。文章來源地址http://www.zghlxwxcb.cn/news/detail-690575.html

到了這里,關于C++算法 —— 分治(2)歸并的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • C++排序算法:歸并排序詳解

    C++排序算法:歸并排序詳解

    一、歸并排序 二、基本算法 ????????1、分離 ????????2、合并 ????????3、圖片講解 三、代碼實現(xiàn) ? ? ? ? 1、分離函數(shù) ? ? ? ? 2、合并函數(shù)? ? ? ? ? 3、完整代碼? ? ? ? ? 4、樣例 四、總結 ???????? 歸并排序 (Merge Sort)是建立在歸并操作上的一種既有效又穩(wěn)

    2024年02月12日
    瀏覽(19)
  • 【算法系列篇】分治-歸并

    【算法系列篇】分治-歸并

    上一篇算法文章,我們介紹了分治-快排的算法,今天我將為大家分享關于分治的另外一種算法——歸并。 歸并算法是一種常用的排序算法,它采用分治策略將待排序的數(shù)組分解為更小的子數(shù)組,然后逐步合并這些子數(shù)組以獲得最終的有序數(shù)組。歸并排序的主要思想是將兩個

    2024年02月09日
    瀏覽(24)
  • 算法:分治思想處理歸并遞歸問題

    算法:分治思想處理歸并遞歸問題

    利用歸并思想進行分治也是很重要的一種思路,在解決逆序對的問題上有很大的需求空間 于是首先歸并排序是首先的,歸并排序要能寫出來: 以上為歸并排序基本算法原理,基于這個原理可以解決逆序對問題,逆序對問題通常問法是,給定某一個數(shù)據(jù),在整個數(shù)組中找比這

    2024年02月10日
    瀏覽(22)
  • C++歸并排序算法的應用:計算右側小于當前元素的個數(shù)

    C++歸并排序算法的應用:計算右側小于當前元素的個數(shù)

    給你一個整數(shù)數(shù)組 nums ,按要求返回一個新數(shù)組 counts 。數(shù)組 counts 有該性質: counts[i] 的值是 nums[i] 右側小于 nums[i] 的元素的數(shù)量。 示例 1: 輸入:nums = [5,2,6,1] 輸出:[2,1,1,0] 解釋: 5 的右側有 2 個更小的元素 (2 和 1) 2 的右側僅有 1 個更小的元素 (1) 6 的右側有 1 個更小的元

    2024年02月06日
    瀏覽(20)
  • 歸并算法:分治而治的高效算法大揭秘(圖文詳解)

    歸并算法:分治而治的高效算法大揭秘(圖文詳解)

    ?? 鴿芷咕 :個人主頁 ??? 個人專欄 : 《數(shù)據(jù)結構算法》《粉絲福利》 ??生活的理想,就是為了理想的生活! 歸并算法是我們算法中最常見的算法之一,其思想非常巧妙。本身歸并是只能歸并有序數(shù)組但是當我們利用了二路歸并分治法之后,就可以使用歸并的思想來幫我

    2024年02月03日
    瀏覽(21)
  • 【數(shù)據(jù)結構與算法】歸并排序詳解:歸并排序算法,歸并排序非遞歸實現(xiàn)

    【數(shù)據(jù)結構與算法】歸并排序詳解:歸并排序算法,歸并排序非遞歸實現(xiàn)

    歸并排序是一種經(jīng)典的排序算法,它使用了分治法的思想。下面是歸并排序的算法思想: 遞歸地將數(shù)組劃分成較小的子數(shù)組,直到每個子數(shù)組的長度為1或者0。 將相鄰的子數(shù)組合并,形成更大的已排序的數(shù)組,直到最終得到一個完全排序的數(shù)組。 歸并排序的過程可以分為三

    2024年01月22日
    瀏覽(32)
  • 【算法專題】分治 - 快速排序

    做題鏈接 - Leetcode -75.顏色分類 題目 :給定一個包含紅色、白色和藍色、共 n 個元素的數(shù)組 nums ,原地對它們進行排序,使得相同顏色的元素相鄰,并按照紅色、白色、藍色順序排列。 我們使用整數(shù) 0、 1 和 2 分別表示紅色、白色和藍色。 必須在不使用庫內(nèi)置的 sort 函數(shù)的情

    2024年02月05日
    瀏覽(32)
  • 【算法】排序——歸并排序和計數(shù)排序

    【算法】排序——歸并排序和計數(shù)排序

    ?========================================================================= 主頁點擊直達:個人主頁 我的小倉庫:代碼倉庫 C語言偷著笑:C語言專欄 數(shù)據(jù)結構挨打小記: 初階數(shù)據(jù)結構專欄 Linux被操作記: Linux專欄 LeetCode刷題掉發(fā)記: LeetCode刷題 算法頭疼記: 算法專欄? ========================

    2024年02月08日
    瀏覽(26)
  • 【排序算法】歸并排序與快速排序

    【排序算法】歸并排序與快速排序

    ??? ??????? 歡迎來到小林的博客!! ?????????博客主頁:??小林愛敲代碼 ?????????博客專欄:?? 算法訓練筆記 ?????????社區(qū) :?? 進步學堂 ?????????歡迎關注:??點贊??收藏??留言 今天給大家分享兩種排序,一種是

    2024年01月19日
    瀏覽(50)
  • 【初階算法4】——歸并排序的詳解,及其歸并排序的擴展

    【初階算法4】——歸并排序的詳解,及其歸并排序的擴展

    目錄 前言 學習目標: 學習內(nèi)容: 一、介紹歸并排序 1.1 歸并排序的思路 1.2 歸并排序的代碼 1.2.1 mergesort函數(shù)部分? 1.2.2 process函數(shù)部分? 1.2.3 merge函數(shù)部分? 二、AC兩道經(jīng)典的OJ題目 題目一:逆序對問題 題目二:小和問題? 三、練習一道LeetCode的題目 四、總結在什么情況下使

    2024年02月08日
    瀏覽(44)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包