算法分析—— 《歸并排序》

《排序數組》

題目描述:

給你一個整數數組 nums,請你將該數組升序排列。

你必須在 不使用任何內置函數 的情況下解決問題,時間復雜度為 O(nlog(n)),并且空間復雜度盡可能小。

示例 1:

輸入:nums = [5,2,3,1]
輸出:[1,2,3,5]

示例 2:

輸入:nums = [5,1,1,2,0,0]
輸出:[0,0,1,1,2,5]

代碼實現:

class Solution 
{
public:vector<int> tmp;vector<int> sortArray(vector<int>& nums) {tmp.resize(nums.size());MergeSort(nums, 0, nums.size() - 1);return nums;}void MergeSort(vector<int>& nums, int l, int r){if(l >= r) return;int mid = (r + l) >> 1;MergeSort(nums, l, mid);MergeSort(nums, mid + 1, r);int cur1 = l, cur2 = mid + 1, i = 0;while(cur1 <= mid && cur2 <= r) tmp[i++] = nums[cur1] >= nums[cur2] ? nums[cur2++] : nums[cur1++];while(cur1 <= mid) tmp[i++] = nums[cur1++];while(cur2 <= r) tmp[i++] = nums[cur2++];for(int i = l; i <= r; ++i) nums[i] = tmp[i - l];}
};

代碼解析:

對于同一種排序題目來說,不僅僅要去掌握快速排序,接觸其他的排序新思路也尤為重要,不管是歸并排序還是快速排序,其本質的思路就是兩個字 —— 分治。

所以歸并排序是最簡單的,利用遞歸的思路,我們就認為這個遞歸操作一定可以做到,那么最終就是實現一個「合并兩個有序數組」的操作。

那這個操作很簡單,利用雙指針就可以非常輕松的實現了,在這里我就不過多贅述,因為確實不難。

《交易逆序對的總數》

題目描述:

在股票交易中,如果前一天的股價高于后一天的股價,則可以認為存在一個「交易逆序對」。請設計一個程序,輸入一段時間內的股票交易記錄 record,返回其中存在的「交易逆序對」總數。

示例 1:

輸入:record = [9, 7, 5, 4, 6]
輸出:8
解釋:交易中的逆序對為 (9, 7), (9, 5), (9, 4), (9, 6), (7, 5), (7, 4), (7, 6), (5, 4)。

代碼實現:

class Solution 
{
public:vector<int> tmp;int reversePairs(vector<int>& record) {tmp.resize(record.size());return mergesort(record, 0, record.size() - 1);}int mergesort(vector<int>& record, int left, int right){if(left >= right) return 0;int mid = (left + right) >> 1;int ret = 0;ret += mergesort(record, left, mid);ret += mergesort(record, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = 0;while(cur1 <= mid && cur2 <= right){if(record[cur1] <= record[cur2]) tmp[i++] = record[cur1++];else {ret += (mid - cur1 + 1);tmp[i++] = record[cur2++];} }while(cur1 <= mid) tmp[i++] = record[cur1++];while(cur2 <= right) tmp[i++] = record[cur2++];for(int i = left; i <= right; ++i){record[i] = tmp[i - left];}return ret;}};

代碼解析:

題目意思很好理解,就是定一個數字,然后去后面找有沒有比這個數小的,記住一定是要去后面找。

最簡單的解法就是利用雙指針套兩層for循環直接暴力解決,但是最終會超時,這就很尷尬。

第二個方法,就是利用分治歸并的思路來解決題目。

我們最主要的研究可以轉換成「找出該數前,有多少個數比我大」

那現在假設我們利用了「歸并」將數組排好了升序了,但是還沒有「合并兩個有序數組」,大致的情況如下:

因為這個判斷也需要指針移動,所以我們就可以在排序的過程中,就將答案給算出來。

因為單調性,所以在nums[cur1] > nums[cur2]的情況下,cur1后面的數都大于nums[cur2]

《計算右側小于當前元素的個數》

題目描述:

給你一個整數數組 nums ,按要求返回一個新數組 counts 。數組 counts 有該性質: counts[i] 的值是 nums[i] 右側小于 nums[i] 的元素的數量。

示例 1:

輸入:nums = [5,2,6,1]
輸出:[2,1,1,0] 
解釋:
5 的右側有 2 個更小的元素 (2 和 1)
2 的右側僅有 1 個更小的元素 (1)
6 的右側有 1 個更小的元素 (1)
1 的右側有 0 個更小的元素

示例 2:

輸入:nums = [-1]
輸出:[0]

示例 3:

輸入:nums = [-1,-1]
輸出:[0,0]

代碼實現:

class Solution 
{
public:vector<pair<int, int>> tmp;     // 追蹤numsvector<int> ret;                // 接受答案vector<pair<int, int>> assist;  // 哈希綁定(原數據 + 下標)vector<int> countSmaller(vector<int> &nums){for (int i = 0; i < nums.size(); ++i){assist.push_back(make_pair(nums[i], i));}ret.resize(nums.size());tmp.resize(assist.size());Mergesort(assist, 0, nums.size() - 1);return ret;}void Mergesort(vector<pair<int, int>> &assist, int left, int right){if (left >= right) return;int mid = (right + left) >> 1;Mergesort(assist, left, mid);Mergesort(assist, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = 0;while (cur1 <= mid && cur2 <= right){if (assist[cur1].first <= assist[cur2].first) tmp[i++] = assist[cur2++];else{ret[assist[cur1].second] += right - cur2 + 1;tmp[i++] = assist[cur1++];}}while (cur1 <= mid) tmp[i++] = assist[cur1++];while (cur2 <= right) tmp[i++] = assist[cur2++];for (int i = left; i <= right; ++i) assist[i] = tmp[i - left];}};

代碼解析:

這道題目總體來說,與上一道題的算法思路一樣,上一道題是記錄有多少個前面大于后面的數字,而這道題是將每個坐標的數字統計起來,然后將確切的數據按照下標統計。

所以使用歸并排序,我們無法固定住下標,因為下標會隨著排序而發生變化。所以這正是我們需要去解決的。

一開始我考慮使用哈希表,但是數組可能會出現重復數據,所以哈希表pass了,但是我們可以仍然采用哈希的算法思路,將數據和下標綁定在一起。那么這時候我們可以使用vector<pair<int, int>>來模擬哈希表。

拿題目自帶的例子:

這樣子在排序改變數據位置的同時,下標也隨之改變了。

然后也是基于上一道題了,不過這里我們不應該排「升序」,而是排「降序」,因為我們是要找右側有多少個元素比自己小,那竟然如此我們可以畫個圖理解理解。

因為單調性,所以nums[cur1]大于cur2后面的全部數。

剩下的思路也是一樣的,只是需要注意pair的first和seconde的取值。

《翻轉對》

題目描述:

給定一個數組 nums ,如果 i < jnums[i] > 2*nums[j] 我們就將 (i, j) 稱作一個重要翻轉對****。

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

示例 1:

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

示例 2:

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

注意:

  1. 給定數組的長度不會超過50000
  2. 輸入數組中的所有數字都在32位整數的表示范圍內。

代碼實現:

class Solution 
{
public:vector<int> tmp;int reversePairs(vector<int>& nums) {tmp.resize(nums.size());return MergeSort(nums, 0, nums.size() - 1);}int MergeSort(vector<int>& nums, int left, int right){if(left >= right) return 0;int mid = (left + right) >> 1;int ret = 0;ret += MergeSort(nums, left, mid);ret += MergeSort(nums, mid + 1, right);int cur1 = left, cur2 = mid + 1, i = 0;while(cur1 <= mid){while(cur2 <= right && nums[cur1] / 2.0 <= nums[cur2]) ++cur2;if(cur2 > right) break;ret += (right - cur2 + 1);++cur1;}cur1 = left, cur2 = mid + 1;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];return ret;}};

代碼解析:

一樣,這道題和前面的內容算法一樣,只不過這里是判斷是否大于2倍。

那在這里我們在實現「合并兩個有序數組」之前,就可以先通過雙指針進行一次判斷,再去排序,因為你無法控制是以2倍為標準然后向右移動還是統計數據,而且經過排序后,數據也會亂了,因此我們必須在排序之前就通過雙指針做好統計。

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

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

相關文章

UEFI Spec 學習筆記---11 - Protocols — UEFI Driver Model(1)

11.UEFI Driver Model 遵循 UEFI model 的 EFI driver 是不允許去遍歷所有的 controller 來識別需要安裝到哪個 controller 上的&#xff0c;而是通過 EFI_BOOT_SERVICES 的 ConnectController 和調用 Binding Driver 來實現&#xff1b; 具體實現如下&#xff1a; CoreConne…

10G EPON光模塊

一、10G EPON對稱光模塊 工作模式&#xff1a;上行突發接收、下行連續發射。 工作原理&#xff1a;當需要發送信號時&#xff0c;系統信號通過光模塊的電接口把信號傳送到驅動芯片&#xff0c;芯片處理后&#xff0c;驅動激光器發出調制光信號&#xff0c;經光纖發到遠端&…

整合SaToken 實現登錄功能

整合SaToken 實現登錄功能 1.整合redis 1.1添加相關依賴 // 省略...<!-- Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Redi…

Vue 項目中逐步引入 TypeScript 的類型檢查

在現有的 Vue 項目中逐步引入 TypeScript 的類型檢查 本文源于一道面試題&#xff1a;注&#xff1a;兩種問法一個意思哈&#xff01;&#xff01; 問題一&#xff1a;“ 老項目Js寫的&#xff0c;如何輕量方式享受 ts 類型&#xff1f;” 問題二&#xff1a;“如何 在現有的 …

python后端調用Deep Seek API

python后端調用Deep Seek API 需要依次下載 ●Ollama ●Deepseek R1 LLM模型 ●嵌入模型nomic-embed-text / bge-m3 ●AnythingLLM 參考教程&#xff1a; Deepseek R1打造本地化RAG知識庫:安裝部署使用詳細教程 手把手教你&#xff1a;deepseek R1基于 AnythingLLM API 調用本地…

本地部署MindSearch(開源 AI 搜索引擎框架),然后上傳到 hugging face的Spaces——L2G6

部署MindSearch到 hugging face Spaces上——L2G6 任務1 在 官方的MindSearch頁面 復制Spaces應用到自己的Spaces下&#xff0c;Space 名稱中需要包含 MindSearch 關鍵詞&#xff0c;請在必要的步驟以及成功的對話測試結果當中 實現過程如下&#xff1a; 2.1 MindSearch 簡…

matlab下載安裝圖文教程

【matlab介紹】 MATLAB是一款由美國MathWorks公司開發的專業計算軟件&#xff0c;主要應用于數值計算、可視化程序設計、交互式程序設計等高科技計算環境。以下是關于MATLAB的簡要介紹&#xff1a; MATLAB是MATrix LABoratory&#xff08;矩陣實驗室&#xff09;的縮寫&#…

捷米特 JM - RTU - TCP 網關應用 F - net 協議轉 Modbus TCP 實現電腦控制流量計

一、項目背景 在某工業生產園區的供水系統中&#xff0c;為了精確監測和控制各個生產環節的用水流量&#xff0c;需要對分布在不同區域的多個流量計進行集中管理。這些流量計原本采用 F - net 協議進行數據傳輸&#xff0c;但園區的監控系統基于 Modbus TCP 協議進行數據交互&…

4.1 Hugging Face Datasets實戰:構建企業級數據流水線

Hugging Face Datasets實戰:構建企業級數據流水線 一、Datasets庫核心優勢 1.1 企業級數據處理需求全景 # 支持的數據格式示例 data_formats = {"結構化數據": ["CSV", "Parquet", "SQL"]

深入解析隊列與廣度優先搜索(BFS)的算法思想:原理、實現與應用

目錄 1. 隊列的基本概念 2. 廣度優先搜索&#xff08;BFS&#xff09;的基本概念 3. 隊列在BFS中的作用 4. BFS的實現細節 5. C實現BFS 6. BFS的應用場景 7. 復雜度分析 8. 總結 1. 隊列的基本概念 隊列&#xff08;Queue&#xff09;是一種先進先出&#xff08;FIFO, …

【學術投稿-第四屆材料工程與應用力學國際學術會議(ICMEAAE 2025】材料工程與應用力學的探討

重要信息 官網&#xff1a;www.icmeaae.com 時間&#xff1a;2025年3月7-9日 地點&#xff1a;中國西安 簡介 第四屆材料工程與應用力學&#xff08;ICMEAAE 2025&#xff09;將于2025年3月7日至9日在中國西安召開。本次會議將重點討論材料科學、應用力學等領域的最新研究進…

間隔連續問題

間隔連續問題 1. 數據結構&#xff1a;某游戲公司記錄的用戶每日登錄數據 表名&#xff1a;game_user 字段名&#xff1a;id&#xff08;用戶id&#xff09;、dt&#xff08;日期&#xff09; 2. 需求&#xff1a; ① 創建表 ② 計算每個用戶最大的連續登錄天數&#xff0c…

EasyRTC輕量級SDK:智能硬件音視頻通信資源的高效利用方案

在智能硬件這片廣袤天地里&#xff0c;每一份資源的精打細算都關乎產品的生死存亡。隨著物聯網技術的疾速演進&#xff0c;實時音視頻通信功能已成為眾多設備的標配。然而&#xff0c;硬件資源的捉襟見肘&#xff0c;讓開發者們常常陷入兩難境地。EasyRTC&#xff0c;以它的極致…

神經網絡剪枝技術的重大突破:sGLP-IB與sTLP-IB

神經網絡剪枝技術的重大突破:sGLP-IB與sTLP-IB 在人工智能飛速發展的今天,深度學習技術已經成為推動計算機視覺、自然語言處理等領域的核心力量。然而,隨著模型規模的不斷膨脹,如何在有限的計算資源和存儲條件下高效部署這些復雜的神經網絡模型,成為了研究者們亟待解決的…

[AI相關]Unity的C#代碼如何簡寫

是一個某培訓機構的飛行棋教學源碼 不知道&#xff0c;是否有人想知道怎么可以簡寫 &#xff08;這個問AI&#xff0c;DeepSeek也應該找不到答案的&#xff09; 靜態變量 屬性引用 單例 注入 一些UnityEvent特性就不說了。。。 IL 注入 運算符號改寫

【Docker】容器被停止/刪除的方式及命令:全面解析與實踐指南

文章目錄 引言一、容器的生命周期二、停止容器的命令及方式1. docker stop 命令2. docker kill 命令3. docker pause 和 docker unpause 命令4. docker restart 命令 三、刪除容器的命令及方式1. docker rm 命令2. docker container prune 命令3. docker rm 與 docker rmi 的區…

Node.js技術原理分析系列——Node.js調試能力分析

本文由體驗技術團隊屈金雄原創。 Node.js 是一個開源的、跨平臺的 JavaScript 運行時環境&#xff0c;它允許開發者在服務器端運行 JavaScript 代碼。Node.js 是基于 Chrome V8引擎構建的&#xff0c;專為高性能、高并發的網絡應用而設計&#xff0c;廣泛應用于構建服務器端應…

輕松搭建本地大語言模型(二)Open-WebUI安裝與使用

文章目錄 前置條件目標一、安裝 Open-WebUI使用 Docker 部署 二、使用 Open-WebUI&#xff08;一&#xff09;訪問Open-WebUI&#xff08;二&#xff09;注冊賬號&#xff08;三&#xff09;模型選擇&#xff08;四&#xff09;交互 四、常見問題&#xff08;一&#xff09;容器…

阿里云百煉通義大模型

阿里云百煉通義大模型 Part one&#xff08;阿里云百煉大模型&#xff09;一、什么是百煉&#xff08;一&#xff09;調用大模型 二、支持的大模型三、模型總覽四、為什么選擇百煉&#xff1f;五、開始使用百煉Part two一、開發參考二、模型調用&#xff08;一&#xff09;通義…

Golang學習筆記_33——橋接模式

Golang學習筆記_30——建造者模式 Golang學習筆記_31——原型模式 Golang學習筆記_32——適配器模式 文章目錄 橋接模式詳解一、橋接模式核心概念1. 定義2. 解決的問題3. 核心角色4. 類圖 二、橋接模式的特點三、適用場景1. 多維度變化2. 跨平臺開發3. 動態切換實現 四、與其他…