【C++算法】50.分治_歸并_翻轉對

文章目錄

    • 題目鏈接:
    • 題目描述:
    • 解法
    • C++ 算法代碼:
    • 圖解


題目鏈接:

493. 翻轉對


題目描述:

e1a56c57c284100520d1840d3224460e


解法

分治

策略一:計算當前元素cur1后面,有多少元素的兩倍比我cur1小(降序)

利用單調性使用同向雙指針。

6ca12f25aadf9a660c566e1254f800d0

策略二:計算當前元素cur2之前,有多少元素的一半比我cur2大(升序)

8ae918bf3c685ed0b37605b78c2cc096

最后合并兩個有序數組。


C++ 算法代碼:

降序版本

class Solution 
{int tmp[50010];  // 臨時數組,用于歸并排序中合并兩個子數組
public:// 主函數,計算數組中的翻轉對數量int reversePairs(vector<int>& nums) {return mergeSort(nums, 0, nums.size() - 1);  // 調用歸并排序函數}// 歸并排序函數,返回區間[left, right]內的翻轉對數量int mergeSort(vector<int>& nums, int left, int right){if(left >= right) return 0;  // 基本情況:如果區間只有一個元素或為空,翻轉對數量為0int ret = 0;  // 保存翻轉對數量// 1. 先根據中間元素劃分區間int mid = (left + right) >> 1;  // 計算中間位置,相當于 (left + right) / 2// 2. 遞歸計算左右兩側的翻轉對數量ret += mergeSort(nums, left, mid);       // 左半部分翻轉對數量ret += mergeSort(nums, mid + 1, right);  // 右半部分翻轉對數量// 3. 計算跨越左右兩個子數組的翻轉對數量int cur1 = left, cur2 = mid + 1;// 對于左子數組中的每個元素,計算右子數組中有多少元素可以構成翻轉對while(cur1 <= mid) {// 在右子數組中查找第一個小于 nums[cur1]/2 的元素位置// 即滿足 nums[cur2] < nums[cur1]/2 的最小的cur2while(cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) cur2++;if(cur2 > right)  // 如果右子數組中所有元素都不滿足條件break;// 右子數組中從cur2到right的所有元素都能與nums[cur1]構成翻轉對ret += right - cur2 + 1;cur1++;  // 處理左子數組中的下一個元素}// 4. 合并兩個有序子數組(降序合并)cur1 = left;cur2 = mid + 1;int i = left;  // 臨時數組的起始索引// 比較左右子數組元素,較大者先放入臨時數組while(cur1 <= mid && cur2 <= right)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;  // 返回翻轉對總數}
};

升序版本

class Solution 
{int tmp[50010];  // 臨時數組,用于歸并排序中合并兩個子數組
public:// 主函數,計算數組中的翻轉對數量int reversePairs(vector<int>& nums) {return mergeSort(nums, 0, nums.size() - 1);  // 調用歸并排序函數}// 歸并排序函數,返回區間[left, right]內的翻轉對數量int mergeSort(vector<int>& nums, int left, int right){if(left >= right) return 0;  // 基本情況:如果區間只有一個元素或為空,翻轉對數量為0int ret = 0;  // 保存翻轉對數量// 1. 先根據中間元素劃分區間int mid = (left + right) >> 1;  // 計算中間位置,相當于 (left + right) / 2// 2. 遞歸計算左右兩側的翻轉對數量ret += mergeSort(nums, left, mid);       // 左半部分翻轉對數量ret += mergeSort(nums, mid + 1, right);  // 右半部分翻轉對數量// 3. 計算跨越左右兩個子數組的翻轉對數量int cur1 = left, cur2 = mid + 1;// 對于右子數組中的每個元素,計算左子數組中有多少元素可以構成翻轉對while(cur2 <= right) {// 在左子數組中查找第一個大于 2*nums[cur2] 的元素位置// 即滿足 nums[cur1] > 2*nums[cur2] 的最小的cur1while(cur1 <= mid && nums[cur2] >= nums[cur1] / 2.0) cur1++;if(cur1 > mid)  // 如果左子數組中所有元素都不滿足條件break;// 左子數組中從cur1到mid的所有元素都能與nums[cur2]構成翻轉對ret += mid - cur1 + 1;cur2++;  // 處理右子數組中的下一個元素}// 4. 合并兩個有序子數組(升序合并)cur1 = left;cur2 = mid + 1;int i = left;  // 臨時數組的起始索引// 比較左右子數組元素,較小者先放入臨時數組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 j = left; j <= right; j++)nums[j] = tmp[j];return ret;  // 返回翻轉對總數}
};

圖解

例如:nums = [1, 3, 2, 3, 1]

初始化:

  • 原始數組: [1, 3, 2, 3, 1]
  • 我們需要找到所有滿足 i < jnums[i] > 2 * nums[j] 的索引對 (i, j)

第一層遞歸(整個數組):

  • [1, 3, 2, 3, 1] 分為 [1, 3][2, 3, 1]

處理左半部分 [1, 3]:

  • 進一步劃分為 [1][3]
  • 這些是單個元素,不需要計算內部的翻轉對
  • 計算跨越的翻轉對: 沒有跨越的翻轉對(因為兩個子數組只有一個元素)
  • 合并: [3, 1] (降序排序)

處理右半部分 [2, 3, 1]:

  • 進一步劃分為 [2][3, 1]
  • 對于 [3, 1], 遞歸處理:
    • 劃分為 [3][1]
    • 計算跨越的翻轉對: 3 > 2*1, 所以有1個翻轉對
    • 合并: [3, 1] (降序排序)
  • 計算跨越的翻轉對([2] 和 [3, 1]):
    • 對于左子數組的元素2:
      • 檢查右子數組的元素: 2 不大于 2*3, 但2 > 2*1
      • 所以有1個翻轉對
  • 合并: [3, 2, 1] (降序排序)

最后合并 [3, 1][3, 2, 1]:

  • 計算跨越的翻轉對:
    • 對于左子數組的元素3:
      • 檢查右子數組的元素: 3 不大于 2*3, 3 不大于 2*2, 但3 > 2*1
      • 所以有1個翻轉對
    • 對于左子數組的元素1:
      • 檢查右子數組的元素: 1 不大于 2*3, 1 不大于 2*2, 1 不大于 2*1
      • 所以沒有翻轉對
  • 合并: [3, 3, 2, 1, 1] (降序排序)

計算翻轉對總數:

  • 左半部分內部: 0個
  • 右半部分內部: 1+1=2個
  • 跨越左右半部分: 0個

因此,翻轉對總數是 0 + 2 + 0 = 2 個。

這兩個翻轉對分別對應原數組中的:

  1. (1, 4): 索引1處的元素3 > 2*索引4處的元素1
  2. (3, 4): 索引3處的元素3 > 2*索引4處的元素1

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

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

相關文章

深入講解:智能合約中的讀寫方法

前言 在探秘區塊鏈開發:智能合約在 DApp 中的地位及與傳統開發差異一文中我提到對于智能合約中所有的寫入其實都算是交易。而在一個完整的智能合約代碼中最大的兩個組成部分就是讀取和寫入。 本文將為你深入探討該兩者方法之間的區別。 寫方法 寫方法其實就是對區塊鏈這一…

Go語言類型捕獲及內存大小判斷

代碼如下&#xff1a; 類型捕獲可使用&#xff1a;reflect.TypeOf()&#xff0c;fmt.Printf在的%T。 內存大小判斷&#xff1a;len()&#xff0c;unsafe.Sizeof。 package mainimport ("fmt""unsafe""reflect" )func main(){var i , j 1, 2f…

MyBatis Plus 在 ZKmall開源商城持久層的優化實踐

ZKmall開源商城作為基于 Spring Cloud 的高性能電商平臺&#xff0c;其持久層通過 MyBatis Plus 實現了多項深度優化&#xff0c;涵蓋分庫分表、緩存策略、分頁性能、多租戶隔離等核心場景。以下是具體實踐總結&#xff1a; 一、分庫分表與插件集成優化 1. 分庫分表策略 ?Sh…

學習MySQL第七天

夕陽無限好 只是近黃昏 一、子查詢 1.1 定義 將一個查詢語句嵌套到另一個查詢語句內部的查詢 我們通過具體示例來進行演示&#xff0c;這一篇博客更側重于通過具體的小問題來引導大家獨立思考&#xff0c;然后熟悉子查詢相關的知識點 1.2 問題1 誰的工資比Tom高 方…

Nginx 常見面試題

一、nginx常見錯誤及處理方法 1.1 404 bad request 一般原因&#xff1a;請求的Header過大 解決辦法&#xff1a; 配置nginx.conf 相關設置1. client_header_buffer_size 16k; 2. large_client_header_buffers 4 64k;1.2 413 Request Entity Too Large 一般原因&#xff1…

LeetCode 每日一題 2025/3/31-2025/4/6

記錄了初步解題思路 以及本地實現代碼&#xff1b;并不一定為最優 也希望大家能一起探討 一起進步 目錄 3/31 2278. 字母在字符串中的百分比4/1 2140. 解決智力問題4/2 2873. 有序三元組中的最大值 I4/3 2874. 有序三元組中的最大值 II4/4 1123. 最深葉節點的最近公共祖先4/5 1…

Docker Compose 常用命令 運行 docker-compose.yaml

Docker Compose 中有兩個重要的概念 服務 (service)&#xff1a;一個應用的容器&#xff0c;實際上可以包括若干運行相同鏡像的容器實例。 項目 (project)&#xff1a;由一組關聯的應用容器組成的一個完整業務單元&#xff0c;在 docker-compose.yml 文件中定義。 為了更方便…

深度學習中的 Batch 機制:從理論到實踐的全方位解析

一、Batch 的起源與核心概念 1.1 批量的中文譯名解析 Batch 在深度學習領域標準翻譯為"批量"或"批次"&#xff0c;指代一次性輸入神經網絡進行處理的樣本集合。這一概念源自統計學中的批量處理思想&#xff0c;在計算機視覺先驅者Yann LeCun于1989年提出…

Unity Internal-ScreenSpaceShadows 分析

一、代碼結構 // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)Shader "Hidden/Internal-ScreenSpaceShadows" {Properties {_ShadowMapTexture ("", any) "" {} // 陰影貼圖紋理&…

Token+JWT+Redis 實現鑒權機制

TokenJWTRedis 實現鑒權機制 使用 Token、JWT 和 Redis 來實現鑒權機制是一種常見的做法&#xff0c;尤其適用于分布式應用或微服務架構。下面是一個大致的實現思路&#xff1a; 1. Token 和 JWT 概述 Token&#xff1a;通常是一個唯一的字符串&#xff0c;可以用來標識用戶…

RPC與其他通信技術的區別,以及RPC的底層原理

1、什么是 RPC&#xff1f; 遠程過程調用&#xff08;RPC&#xff09; 是一種協議&#xff0c;它允許程序在不同計算機之間進行通信&#xff0c;讓開發者可以像調用本地函數一樣發起遠程請求。 通過 RPC&#xff0c;開發者無需關注底層網絡細節&#xff0c;能夠更專注于業務邏…

簡潔的 PlantUML 入門教程

評論中太多朋友在問&#xff0c;我的文章中圖例如何完成的。 我一直用plantUML,也推薦大家用&#xff0c;下面給出一個簡潔的PlantUML教程。 &#x1f331; 什么是 PlantUML&#xff1f; PlantUML 是一個用純文本語言畫圖的工具&#xff0c;支持流程圖、時序圖、用例圖、類圖、…

互聯網三高-高性能之JVM調優

1 運行時數據區 JVM運行時數據區是Java虛擬機管理的內存核心模塊&#xff0c;主要分為線程共享和線程私有兩部分。 &#xff08;1&#xff09;線程私有 ① 程序計數器&#xff1a;存儲當前線程執行字節碼指令的地址&#xff0c;用于分支、循環、異常處理等流程控制? ② 虛擬機…

淺談StarRocks 常見問題解析

StarRocks數據庫作為高性能分布式分析數據庫&#xff0c;其常見問題及解決方案涵蓋環境部署、數據操作、系統穩定性、安全管控及生態集成五大核心領域&#xff0c;需確保Linux系統環境、依賴庫及環境變量配置嚴格符合官方要求以避免節點啟動失敗&#xff0c;數據導入需遵循格式…

P1332 血色先鋒隊(BFS)

題目背景 巫妖王的天災軍團終于卷土重來&#xff0c;血色十字軍組織了一支先鋒軍前往諾森德大陸對抗天災軍團&#xff0c;以及一切沾有亡靈氣息的生物。孤立于聯盟和部落的血色先鋒軍很快就遭到了天災軍團的重重包圍&#xff0c;現在他們將主力只好聚集了起來&#xff0c;以抵…

大文件上傳之斷點續傳實現方案與原理詳解

一、實現原理 文件分塊&#xff1a;將大文件切割為固定大小的塊&#xff08;如5MB&#xff09; 進度記錄&#xff1a;持久化存儲已上傳分塊信息 續傳能力&#xff1a;上傳中斷后根據記錄繼續上傳未完成塊 塊校驗機制&#xff1a;通過哈希值驗證塊完整性 合并策略&#xff1a;所…

【動手學深度學習】卷積神經網絡(CNN)入門

【動手學深度學習】卷積神經網絡&#xff08;CNN&#xff09;入門 1&#xff0c;卷積神經網絡簡介2&#xff0c;卷積層2.1&#xff0c;互相關運算原理2.2&#xff0c;互相關運算實現2.3&#xff0c;實現卷積層 3&#xff0c;卷積層的簡單應用&#xff1a;邊緣檢測3.1&#xff0…

Opencv計算機視覺編程攻略-第十一節 三維重建

此處重點討論在特定條件下&#xff0c;重建場景的三維結構和相機的三維姿態的一些應用實現。下面是完整投影公式最通用的表示方式。 在上述公式中&#xff0c;可以了解到&#xff0c;真實物體轉為平面之后&#xff0c;s系數丟失了&#xff0c;因而無法會的三維坐標&#xff0c;…

大廠不再招測試?軟件測試左移開發合理嗎?

&#x1f449;目錄 1 軟件測試發展史 2 測試左移&#xff08;Testing shift left&#xff09; 3 測試右移&#xff08;Testing shift right&#xff09; 4 自動化測試 VS 測試自動化 5 來自 EX 測試的寄語 最近兩年&#xff0c;互聯網大廠的招聘中&#xff0c;測試工程師崗位似…

windows10下PointNet官方代碼Pytorch實現

PointNet模型運行 1.下載源碼并安裝環境 GitCode - 全球開發者的開源社區,開源代碼托管平臺GitCode是面向全球開發者的開源社區,包括原創博客,開源代碼托管,代碼協作,項目管理等。與開發者社區互動,提升您的研發效率和質量。https://gitcode.com/gh_mirrors/po/pointnet.pyto…