【分治思想】歸并排序 與 逆序對

歸并排序

歸并排序是一種分治算法,怎么分,怎么治?

  • 分:通過遞歸不斷把數組分成兩半,直到每個子數組只剩 1 個元素(天然有序)
  • 治:把兩個已經排好序的子數組合并成一個有序數組。

把問題分解為簡單子問題,就體現在每個數組只剩一個元素時,那就天然有序了。

模板題

P1177 【模板】排序
在這里插入圖片描述

歸并排序代碼實現

#include<iostream>using namespace std;const int N = 1e5 + 10;int n, a[N], tmp[N]; //a存數據,tmp輔助歸并排序時合并兩個數組 void merge_sort(int left, int right)
{if(left >= right) return; //left == right只有一個元素,有序,返回 //1.數組一分為二 int mid = (left + right) / 2;//2.將左右數組都排好序 merge_sort(left, mid);merge_sort(mid + 1, right);//3.合并左右有序數組到tmp中 int cur1 = left, cur2 = mid + 1, i = left; //i幫助寫入臨時數組 while(cur1 <= mid && cur2 <= right){if(a[cur1] <= a[cur2]) tmp[i++] = a[cur1++];else tmp[i++] = a[cur2++];}while(cur1 <= mid) tmp[i++] = a[cur1++];while(cur2 <= right) tmp[i++] = a[cur2++];//4.將tmp中的[left,right]區間轉移到a的[left,right]區間 for(int j=left;j<=right;j++) a[j] = tmp[j]; //最容易錯的一步,要知道在merge_sort函數中,我們是對[left, right]區間進行排序而不是[0, n] 
}int main()
{cin >> n;for(int i=1;i<=n;i++) cin >> a[i];merge_sort(1,n);for(int i=1;i<=n;i++) cout << a[i] << " ";return 0;
}

時間復雜度

不斷地將數組一分為二,直到只剩下一個元素為止,時間復雜度為 logn;
將 tmp 數組復制到 a 數組,時間復雜度為 n。
總的時間復雜度為 O ( n l o g n ) O(nlogn) O(nlogn)

逆序對

什么是逆序對?

逆序對(Inversion)是指在一個序列中,如果前面的數比后面的數大,那么這兩個數就構成一個逆序對。

逆序對和排序的關系

  • 逆序對的數量衡量了序列的無序程度:逆序對越多,序列越亂;逆序對越少,序列越接近有序。
  • 排序的本質就是消除逆序對

例題

P1908 逆序對
在這里插入圖片描述

分析

首先我們可以想到兩層for循環暴力統計逆序對個數,但是會超時。

我們可以嘗試一下分治的思想,在原數組中找逆序對,相當于先將數組一分為二,在左半邊數組找逆序對,在右半邊數組找逆序對,再一左一右找逆序對,所有的逆序對數量加起來就是原數組的逆序對數量。

于是我們得到了這樣兩個數組,分別對左右求逆序對,這咋求???這還不是要兩層for循環挨個遍歷統計逆序對嗎,這算上二分數組的時間復雜度,現在總時間復雜度干到了 O ( n 2 l o g n ) O(n^2logn) O(n2logn),這能對嗎?
請添加圖片描述
但是當左邊這個數組和右邊這個數組分別有序的時候,再統計逆序對個數就非常方便了。我們選擇一個元素在左邊數組,另一個元素在右邊數組的逆序對,統計邏輯如下:

請添加圖片描述
我們可以發現,這與歸并排序中合并有序數組的流程是一致的。

但是這里就有一個問題:對左邊數組和右邊數組分別排序的話,是否會影響逆序對的統計呢?
不會,因為在統計一左一右的時候,左右數組的逆序對已經統計過了,才形成的左右這樣有序的數組,統計逆序對的統計和歸并排序是同時進行的。
我們仍可以從極限情況分析,當數組的長度為2時,分成左右數組,它們的長度分別為1,于是左右數組中的逆序對個數肯定為0,我們接下來統計一左一右的逆序對個數,統計完之后,這個長度為2的數組也就通過歸并排序變得有序了。另一邊肯定也通過這樣相同的流程得到了一個長度為2的有序數組,然后對它們進行一左一右的逆序對統計,這時候再思考為什么不分別統計左右數組中的逆序對個數呢?因為已經統計過了,它們就是在一左一右合并的過程中統計的。

代碼

#include<iostream>using namespace std; typedef long long LL;const int N = 5e5 + 10;int n, a[N], tmp[N];LL merge(int left, int right)
{if(left >= right) return 0;//1.一分為二int mid = (left + right) >> 1; //2.計算左右數組LL ret = 0; ret += merge(left, mid);ret += merge(mid + 1, right);//3.合并左右數組int cur1 = left, cur2 = mid + 1, i = left;while(cur1 <= mid && cur2 <= right){if(a[cur1] <= a[cur2]) tmp[i++] = a[cur1++];else{tmp[i++] = a[cur2++];ret += mid - cur1 + 1; }	} while(cur1 <= mid) tmp[i++] = a[cur1++];while(cur2 <= right) tmp[i++] = a[cur2++];for(int j=left;j<=right;j++) a[j] = tmp[j];return ret;
}int main()
{cin >> n;for(int i=1;i<=n;i++) cin >> a[i];cout << merge(1,n) << endl;	return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/86988.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/86988.shtml
英文地址,請注明出處:http://en.pswp.cn/web/86988.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SQL參數化查詢:防注入與計劃緩存的雙重優勢

在數據庫操作中&#xff0c;SQL參數化查詢&#xff08;Parameterized Queries&#xff09;是一種非常有效的技術&#xff0c;它不僅可以防止SQL注入攻擊&#xff0c;還可以提高數據庫查詢的效率&#xff0c;尤其是在與計劃緩存&#xff08;Query Plan Caching&#xff09;結合使…

【你怕一E1】- 孰輕孰重如何斷-組合問題的多種情形

摘要 本視頻講解了組合問題的多種情形,包括多選一、多選二、多選三以及分隊問題的解題方法。首先介紹了從不同人數中選人的不同選擇方式,如一百人中選一人有一百種選擇。隨后,詳細講解了有序思考方法在多選二問題中的應用,通過選隊長的方式列舉不同組合情況,并歸納出選擇規…

nginx反向代理的bug

nginx反向代理的bug 問題呈現 當我們配置反向代理的時候查詢error.log的時候我們發現以下的問題 2025/06/29 08:38:47 [error] 7#7: *2 open() “/usr/share/nginx/html/payed/notify” failed (2: No such file or directory), client: 192.168.98.1, server: localhost, r…

MyBatis 動態 SQL 與緩存機制深度解析

在Java持久層技術體系中&#xff0c;MyBatis憑借其靈活的SQL映射和強大的動態SQL能力&#xff0c;成為企業級應用開發的首選框架。本文從動態SQL核心語法、緩存實現原理、性能優化及面試高頻問題四個維度&#xff0c;結合源碼與工程實踐&#xff0c;系統解析MyBatis的核心特性與…

Nuxt 3 中實現跨組件通信方式總結:使用 Pinia、Provide/Inject 或 Props

在開發復雜的 Web 應用時&#xff0c;跨組件通信是一個常見的需求。Nuxt 3 提供了多種方式來實現這一點&#xff0c;包括使用狀態管理工具&#xff08;如 Pinia&#xff09;、Vue 的 provide/inject 機制以及傳統的 props 傳遞。本文將詳細介紹這三種方法&#xff0c;并通過一個…

Java ArrayList 擴容機制

一、ArrayList 簡介 ArrayList 是 Java 集合框架中基于數組實現的可變長度列表&#xff0c;其核心特性是&#xff1a; 支持隨機訪問&#xff08;通過索引&#xff09;支持動態擴容插入/刪除效率較低&#xff08;非尾部操作&#xff09; 二、底層數據結構 // JDK 11 transien…

C++面試題精講系列之數組排序

數組排序是我們經常遇到的筆試題目&#xff0c;給大家盤一下這題到底想考察什么&#xff1f; // 考題如下 void main() {int arr[4] {26,28,24,11};// 請實現一個sortArray函數&#xff0c;對數組arr進行從小到大排序 }考點1&#xff1a;數組做函數參數如何傳遞參&#xff1f;…

Windows10/11 輕度優化 純凈版,12個版本!

系統介紹 鏡像包均基于微軟官方原版系統精心制作&#xff0c;確保系統的原汁原味與穩定性。Windows 10/11&#xff0c;都集成了最新的補丁。版本選對&#xff0c;一鍵安裝到位&#xff0c;全自動無人值守安裝模式。 系統特點 系統進行優化提供了12個系統版本集成了運行庫、…

開發工具IDEA

開發工具IDEA 開發調試&#xff08;debug&#xff09;Maven配置三級目錄 開發調試&#xff08;debug&#xff09; 史上最全的 IDEA Debug 調試技巧&#xff08;超詳細案例&#xff09; Maven配置 idea全局Maven配置 IDEA中Maven配置詳解 有些時候不要配置maven_home這些環境…

GitHub Actions與AWS OIDC實現安全的ECR/ECS自動化部署

引言 在現代云原生應用開發中,實現安全、高效的CI/CD流程至關重要。本文將詳細介紹如何利用GitHub Actions和AWS OIDC(OpenID Connect)構建一個無需長期憑證的安全部署管道,將容器化應用自動部署到Amazon ECR和ECS服務。 架構概述 整個解決方案的架構包含三個主要部分:…

一、MongoDB安裝-二進制安裝

下載tar包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.21.tgz wget https://downloads.mongodb.com/compass/mongosh-2.5.3-linux-x64.tgz安裝 解壓 tar xf mongodb-linux-x86_64-rhel70-7.0.21.tgz cp mongodb-linux-x86_64-rhel70-7.0.21/bi…

學習日志03 ETF 基礎數據可視化分析與簡易管理系統

1 代碼的選擇和改進 import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from ipywidgets import (AppLayout, Dropdown, Button, Output, VBox, HBox, Label, Layout, SelectMultiple,IntSlider, FloatSlider, Checkbox, Text, Select) from IPytho…

[Python] -基礎篇7-新手常見Python語法錯誤及解決方案

Python 以其簡潔明了的語法引人入勝,但對于初學者而言,仍然容易遭遇各類語法錯誤。本文總結了 Python 語言日常編寫中最常見的語法錯誤類型,并提供解決方案和正確寫法,幫助新手快速突破編程路上的一道道埋伏。 1. 拼寫錯誤 (SyntaxError) 這是最基本也最常見的錯誤類型。…

位運算實戰:數值構造終極優化

位運算優化實戰&#xff1a;數值構造問題詳解 今天我們將深入分析一個有趣的位運算優化問題&#xff0c;這個問題展示了如何通過巧妙的預處理和貪心算法來高效解決數值構造問題。 問題背景與定義 給定一個初始值x&#xff08;0 ≤ x ≤ m&#xff09;和一系列位運算操作&…

nosql項目:基于 Redis 哨兵模式的鮮花預訂配送系統

1 鮮花預訂配送系統概述 1.1 項目背景 鮮花預訂系統是一個實時處理用戶訂單、庫存管理和配送跟蹤的平臺。系統需要處理大量并發訂單&#xff0c;實時更新鮮花庫存狀態&#xff0c;并跟蹤配送進度。傳統關系型數據庫難以應對高并發的訂單處理和實時庫存更新需求&#xff0c;因…

中心效應:多中心臨床試驗的關鍵考量

一、中心效應的來源與影響 1.1 常見來源 1.1.1 患者異質性 中心間基線特征差異(如疾病嚴重度、合并癥比例) 1.1.2 操作差異 給藥規范(如輸液速度)、隨訪依從性、數據記錄質量 1.1.3 評估偏倚 影像學判讀標準(如RECIST)、實驗室檢測方法(如中心實驗室 vs 本地實驗室) …

Redis 實現消息隊列

一、為什么選擇 Redis 作為消息隊列&#xff1f; 在分布式系統架構中&#xff0c;消息隊列是實現異步通信和解耦的核心組件。Redis 作為一個高性能的內存數據庫&#xff0c;憑借其卓越的速度和豐富的數據結構&#xff0c;成為輕量級消息隊列的理想選擇&#xff1a; 1.1 核心優…

(3)pytest的setup/teardown

1. 簡介 學過unittest的都知道里面用前置和后置setup和teardown非常好用&#xff0c;在每次用例開始前和結束后都去執行一次。 當然還有更高級一點的setupClass和teardownClass&#xff0c;需配合classmethod裝飾器一起使用&#xff0c;在做selenium自動化的時候&#xff0c;它…

Starrocks存算一體和存算分離

網上整理了一下starrocks兩種部署方式的區別差異性&#xff0c;個人感覺生產環境還是盡量存算分離部署&#xff0c;防止資源爭奪等問題影響線上生產數據&#xff0c;雖然存算一體部署起來更方便一些 &#x1f4ca; 1. 架構設計 存算一體&#xff1a; 節點類型&#xff1a;僅包含…

多線程編程 ----線程主動退出pthread_exit與線程被動退出pthread_cancel

主動退出 pthread_exit 與 pthread_cancel 的區別 1. 核心區別 特性pthread_exitpthread_cancel調用者線程自身調用&#xff0c;主動退出。其他線程調用&#xff0c;異步請求終止目標線程。行為方式立即終止線程&#xff0c;資源需手動釋放。發送取消請求&#xff0c;線程在取…