LeetCode算法日記 - Day 27: 計算右側小于當前元素的個數、翻轉對

目錄

1. 計算右側小于當前元素的個數

1.1 題目解析

1.2 解法

1.3 代碼實現

2. 翻轉對

2.1 題目解析

2.2 解法

2.3 代碼實現


1. 計算右側小于當前元素的個數

315. 計算右側小于當前元素的個數 - 力扣(LeetCode)

給你一個整數數組?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]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

1.1 題目解析

  • 題目本質

    對每個位置 i,統計它右側有多少元素 < nums[i]。這是“離線統計 + 有序累積”的典型問題:如果能讓“右側區域”保持有序,那么當一個左側元素要“落位”時,就能一次性把比它小的右側元素數目加上去。

  • 常規解法:對每個 i 向右掃一遍計數,或把每個 i 與其右邊所有元素比較。
    復雜度 O(n2),n 最多 1e5,超時。

  • 問題分析:O(n2) 不行;要降低到 O(n log n)。要么用“平衡樹/樹狀數組/線段樹”邊插邊查,要么在“歸并排序”的有序合并過程中順手統計。

  • 思路轉折:用 歸并排序(分治)。關鍵是不直接搬值,而是搬“原始下標”

    • 比較用 nums[index[*]];

    • 計數寫回 counts[index[*]]。
      這樣既能用數值排隊,又不丟原始位置,統計才能落對人。

1.2 解法

算法思想
維護一個下標數組 index,對下標做歸并:

????????降序歸并 + 一次性加法:左右兩段都保持降序。若 nums[left] > nums[right],則右半段從 cur2 到 right 的所有元素都更小,直接 += (right - cur2 + 1) 并把左元素出列;否則先出右元素。

i)初始化:index[i]=i,counts 全 0,準備 tmp 臨時數組。

ii)分治:mergeSort(nums, left, right)。

iii)合并:

  • 指針 cur1?=left, cur2 =mid+1,k 寫入 tmp。

  • 若 nums[index[cur1]] <=?nums[index[cur2]]
    tmp[k++]=index[cur2++]。

  • 否則:counts[index[cur1]] += (right - j + 1)
    tmp[k++]=index[cur1++]。

  • 掃尾:
    while (cur1 <= mid) tmp[k++] = index[cur1++];
    while (cur2 <= right) tmp[k++] = index[cur2++];

  • 回寫:
    for (int j?= left; j?<= right; j++) index[j] = tmp[j?- left];

iiii)返回 counts 的列表形式。

易錯點

  • 只搬下標,不搬值:比較寫 nums[index[*]],統計寫 counts[index[*]]。

  • 回寫的是 index,不是 nums:index[j]=tmp[j-left] 或讓 k 從 left 開始寫

  • 注意 while 循環里比大小時判斷的條件

  • 多層歸并要累加:counts[...] += ...,不能覆蓋。

  • tmp 不是答案數組,它只是合并時的 輔助排序區,歸并用的臨時緩沖區,幫助我們把當前區間 [left..right] 合并成有序;排序這一步是必須的,因為我們借助“有序”的過程,才能在 O(n log n) 里順手統計“右邊更小”的個數。

  • counts:是真正的答案數組,counts[cur1] 表示 nums[cur1] 右側比它小的數量,最后返回它即可。

  • k++ 只是為了推進左半區的掃描,別忘了這個數組是記錄下標而不是原始數組的值,所以要推進下標數組的下標值。

  • index 數組的作用是“保持數值和原始下標之間的映射關系不丟失”。

1.3 代碼實現

import java.util.*;class Solution {int[] index;   // 記錄每個元素的“原始下標”,在歸并過程中只搬動下標int[] tmp;     // 臨時數組,用來輔助歸并排序(保存下標,不保存值)int[] counts;  // 結果數組,counts[i] = nums[i] 右側比它小的數量public List<Integer> countSmaller(int[] nums) {int n = nums.length;tmp = new int[n];counts = new int[n];index = new int[n];// 初始化下標數組,初始時 index[i] = ifor (int i = 0; i < n; i++) {index[i] = i;}// 分治歸并排序mergeSort(nums, 0, n - 1);// 把 counts 數組轉成 List<Integer> 返回List<Integer> list = new ArrayList<>(n);for (int v : counts) list.add(v);return list;}public void mergeSort(int[] nums, int left, int right) {if (left >= right) return;  // 遞歸基:區間只有一個元素時結束int mid = left + (right - left) / 2;// 遞歸排序左半區mergeSort(nums, left, mid);// 遞歸排序右半區mergeSort(nums, mid + 1, right);int cur1 = left, cur2 = mid + 1, k = 0;// 合并兩個有序區間(這里用“降序”方式)while (cur1 <= mid && cur2 <= right) {if (nums[index[cur1]] <= nums[index[cur2]]) {// 如果右邊的值更大或相等,先把右邊的下標放進 tmptmp[k++] = index[cur2++];} else {// 如果左邊的值更大:// 說明右邊 [cur2..right] 的元素全都比它小counts[index[cur1]] += (right - cur2 + 1);// 把這個左邊元素的下標放進 tmptmp[k++] = index[cur1++];}}// 把左半區剩余元素拷貝進 tmpwhile (cur1 <= mid) tmp[k++] = index[cur1++];// 把右半區剩余元素拷貝進 tmpwhile (cur2 <= right) tmp[k++] = index[cur2++];// 回寫:把 tmp 里的結果拷回到 index 數組對應區間for (int j = left; j <= right; j++) {index[j] = tmp[j - left];}}
}

復雜度分析

  • 時間:分治 + 合并為 O(n log n),每層合并線性。

  • 空間:index/tmp/counts 為 O(n),遞歸棧 O(log n)。

2. 翻轉對

493. 翻轉對 - 力扣(LeetCode)

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

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

示例 1:

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

示例 2:

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

注意:

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

2.1 題目解析

  • 題目本質:統計所有滿足 i < j 且 nums[i] > 2 * nums[j] 的二元組數量。這是一個“離線統計 + 有序累積”的經典范式:如果左右兩段各自有序,就能用雙指針線性地數出跨段滿足條件的配對數量。

  • 常規解法:雙重循環枚舉 (i, j),逐對判斷是否 nums[i] > 2*nums[j]。時間復雜度 O(n^2),n 最多可到 5e4,顯然超時。

  • 問題分析:要把復雜度壓到 O(n log n)。兩條常見路徑:
    1)平衡樹 / 樹狀數組 / 線段樹做“邊插邊查”;
    2)分治歸并:在“合并”前用雙指針數跨段配對,再做標準歸并。

  • 思路轉折:采用分治歸并。關鍵點:

    • 先數對,后歸并:當左右段([left..mid] 與 [mid+1..right])各自已升序時,固定左段的 i,右段用 j 單調右移,線性統計滿足 nums[i] > 2*nums[j] 的個數。

    • 用 long 比較避免溢出::寫成 (long)nums[i] > 2L * (long)nums[j],不要用 /2.0 的浮點比較。

    • 歸并階段使用標準升序合并,保持下一層統計的前提(左右各自升序)。

2.2 解法

算法思想

分治:mergeSort(left, right)。在回溯(合并)前,借助“兩側各自升序”,對每個 i ∈ [left..mid],移動 j 直到不滿足條件為止,累計 j - (mid + 1)。再做一次標準升序歸并,保證整體有序供更高層使用。

i)遞歸到底:left >= right 返回。

ii)遞歸左右:mergeSort(left, mid)mergeSort(mid+1, right)

iii)先統計

  • j = mid + 1;

  • 對每個 i = left..mid:while (j <= right && (long)nums[i] > 2L * (long)nums[j]) j++;

  • 累加 result += (j - (mid + 1))。

iiii)再歸并(升序):常規雙指針把 [left..mid] 與 [mid+1..right] 合并到 tmp,再回寫。

iiiii)返回最終 result。

易錯點

  • 不要邊合并 邊用 (right - cur2 + 1) 一把加:那是普通逆序對 nums[i] > nums[j] 的套路,對 > 2*nums[j] 不成立。

  • 比較必須用 long:2 * nums[j] 在 int 里可能溢出。

  • 不要用/2.0:浮點精度 + 負數邊界容易出錯,也不必要。

  • 雙計數陷阱:要么用全局 result,要么函數返回值累計,二者不要混用

  • 合并要升序:保證下一層“先數對”的前提(左右各自已升序)。

  • 指針單調:統計階段 j 只右移不回退,整體線性。

2.3 代碼實現

import java.util.*;class Solution {int[] tmp;int result;public int reversePairs(int[] nums) {tmp = new int[nums.length];mergeSort(nums, 0, nums.length - 1);return result;}// 只做副作用統計與排序,不用返回值累計public void mergeSort(int[] nums, int left, int right){if (left >= right) return;int mid = left + (right - left) / 2;mergeSort(nums, left, mid);mergeSort(nums, mid + 1, right);// 先統計:左右兩段各自已升序int j = mid + 1;for (int i = left; i <= mid; i++) {while (j <= right && (long)nums[i] > 2L * (long)nums[j]) j++;// 右半段 [mid+1, j-1] 都滿足 nums[i] > 2*nums[?]result += (j - (mid + 1));}// 再歸并:標準升序合并int cur1 = left, cur2 = mid + 1, k = 0;while (cur1 <= mid && cur2 <= right) {if (nums[cur1] <= nums[cur2]) {tmp[k++] = nums[cur1++];} else {tmp[k++] = nums[cur2++];}}while (cur1 <= mid)  tmp[k++] = nums[cur1++];while (cur2 <= right) tmp[k++] = nums[cur2++];// 回寫for (int t = 0; t < k; t++) {nums[left + t] = tmp[t];}}
}

復雜度分析

  • 時間:每層“先數對”用兩個單調指針線性掃描 O(n),合并 O(n),層數 O(log n),總體 O(n log n)。

  • 空間:輔助數組 tmp O(n),遞歸棧 O(log n)。

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

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

相關文章

基于SamOut的音頻Token序列生成模型訓練指南

通過PyTorch實現從音頻特征到語義Token的端到端序列生成&#xff0c;適用于語音合成、游戲音效生成等場景。&#x1f9e0; 模型架構與核心組件 model SamOut(voc_sizevoc_size, # 詞匯表大小&#xff08;4098目錄名特殊Token&#xff09;hidden_sizehidden_size, …

AWD攻防總結

基本防守策略 1、改用戶密碼和服務密碼 1&#xff09;改linux用戶密碼&#xff1a; #passwd 如果有權限就刪除用戶&#xff1a; #userdel -r [用戶名] 2&#xff09;改mysql密碼&#xff1a; #update mysql.user set passwordpassword(密碼) where userroot; 刪除匿名用戶&…

Android14 基于Configfs的USB動態配置init.usb.configfs.rc

1 Android14 USB子系統啟動以及動態切換的init.usb.rc 2 Android14 基于Configfs的USB動態配置init.usb.configfs.rc 3 Android14 高通平臺的USB子系統啟動和動態配置init.qcom.usb.rc 1. 什么是ConfigFS ConfigFS 是 Linux 內核提供的一種用戶空間可配置的偽文件系統在Linu…

2025年KBS SCI1區TOP,矩陣差分進化算法+移動網絡視覺覆蓋無人機軌跡優化,深度解析+性能實測

目錄1.摘要2.系統模型和問題表述3.矩陣差分進化算法4.結果展示5.參考文獻6.算法輔導應用定制讀者交流1.摘要 本文提出了一種面向無人機&#xff08;UAV&#xff09;新型軌跡優化方法&#xff0c;以實現對地面移動節點的高效視覺覆蓋。與傳統方法不同&#xff0c;該方法顯式考慮…

Python OpenCV圖像處理與深度學習:Python OpenCV圖像幾何變換入門

圖像變換&#xff1a;掌握OpenCV中的幾何變換 學習目標 通過本課程&#xff0c;學員們將能夠理解圖像的幾何變換原理&#xff0c;包括縮放、旋轉和平移&#xff0c;并能夠使用Python和OpenCV庫實現這些變換。本課程將通過理論講解與實踐操作相結合的方式&#xff0c;幫助學員們…

Redis Windows 7.0.5 安裝教程(附exe/msi下載+環境配置+命令測試)

?第一步&#xff1a;下安裝包? 打開瀏覽器&#xff08;比如 Edge 或 Chrome&#xff09;&#xff0c;復制這個鏈接到地址欄敲回車&#xff1a; https://pan.quark.cn/s/31912e0d0443 進去后往下翻&#xff0c;找名字帶 ?**redis-7.0.5? 的文件&#xff0c;?選那個 .exe 結…

數據結構(單鏈表)

目錄 1.鏈表的概念及結構 2.單鏈表的應用 2.1 打印鏈表 2.2申請新節點 2.3插入&#xff08;尾刪和頭刪&#xff09; 2.4刪除&#xff08;尾刪和頭刪&#xff09; 2.5查找 2.6任意位置插入 2.7刪除指定位置的元素 2.8 銷毀鏈表 3.總結 1.鏈表的概念及結構 &#xff…

電腦沒加域卻能獲取到IP地址

企業網絡管理的核心邏輯&#xff01;電腦沒加域卻能獲取到IP地址&#xff0c;這完全是一種刻意為之的安全設計&#xff0c;而不是網絡故障。 簡單來說就是&#xff1a;“給你IP&#xff0c;但不給你權限。” 這背后是一套完整的 網絡準入控制&#xff08;NAC&#xff09; 策略。…

Go語言入門學習筆記

&#x1f4da; 前言 歡迎學習Go語言&#xff01;這份教材假設您是編程零基礎&#xff0c;從最基本的概念開始講解。Go語言&#xff08;也稱為Golang&#xff09;由Google開發&#xff0c;簡單、高效、并發能力強&#xff0c;適合后端開發、系統編程和云計算。 學習建議&#xf…

gradle安裝、配置環境變量、配置阿里源及idea 中配置gradle

下載gradle https://services.gradle.org/distributions/ 配置系統環境變量 新增GRADLE_HOME D:\Information_Technology\App\gradle-8.14.3-bin\gradle-8.14.3 新增GRADLE_USER_HOME D:\Information_Technology\App\gradleHouse 設置 path&#xff0c;新增一行 %GRADLE_…

C# FlaUI win 自動化框架,介紹

一、簡潔介紹 FlaUI 是一套基于 .NET 的 Windows 桌面應用自動化測試庫&#xff0c;支持 Win32、WinForms、WPF、UWP 等多種類型的應用。它基于微軟原生 UI Automation 庫&#xff0c;提供了更現代、易用的 API&#xff0c;適合自動化測試工程師和開發者實現高效、可維護的 UI …

命名空間級別應用 Pod 安全標準

&#x1f3af; 命名空間級別應用 Pod 安全標準 一、創建 Kubernetes 集群&#xff08;使用 kind&#xff09; 使用 kind &#xff08;Kubernetes IN Docker&#xff09;快速創建一個本地集群&#xff1a; kind create cluster --name my-cluster驗證集群是否運行正常&#xff1…

Ubuntu 25.10 Snapshot4 發布。

Ubuntu 25.10 的第四個快照&#xff08;Snapshot 4&#xff09;已于 2025 年 8 月 28 日發布&#xff0c;供開發者和測試人員進行驗證。這是 Ubuntu 25.10 正式發布前的最后一個月度快照&#xff0c;標志著該版本已進入功能凍結階段&#xff0c;預計將在 10 月發布正式版。 Ca…

STM32F2/F4系列單片機解密和芯片應用介紹

STM32F2/F4系列單片機解密和芯片應用介紹STM32F2和STM32F4系列微控制器憑借其出色的性能、豐富的外設接口和強大的連接能力&#xff0c;在很多對計算能力和實時性有要求的領域都有應用。同時&#xff0c;芯片解密的價格因其型號、加密技術等因素差異較大。&#x1f9ed; 重要提…

250901-BookStack跨服務器從Rootless-Docker到Rootful-Docker的備份遷移及服務啟動

下面給你一套「可離線、最小停機」的遷移步驟&#xff0c;從 A&#xff08;rootless&#xff09;搬到 B&#xff08;rootful&#xff09;。思路是&#xff1a;停 A → 打包數據卷 → 傳到 B → 還原 → 用同版本鏡像啟動 → 驗證。整套操作不依賴公網&#xff0c;只用你已有的離…

(Redis)Redis 分布式鎖及改進策略詳解

一、為什么需要分布式鎖在單機應用中&#xff0c;synchronized 或 ReentrantLock 足以解決并發問題。但在 分布式系統 中&#xff0c;多臺服務器之間共享同一個資源時&#xff0c;如果沒有鎖&#xff0c;很可能出現 超賣、重復扣減、數據不一致 等問題。 因此&#xff0c;分布式…

Linux應用開發-windows,linux環境下相關工具

VS Code Remote - SSH 虛擬機部分的操作 sudo systemctl status sshsudo apt update sudo apt install openssh-server sudo systemctl start ssh sudo systemctl enable ssh # 設置開機自啟hostname -IVS Code部分的操作 安裝 Remote - SSH 插件 vscode右下角出現&#xff…

Java泛型通配符詳解:搞懂?/extends/super用法,避開集合操作踩坑點

上次跟你們聊了泛型的基礎用法&#xff0c;今天接著往下說 —— 泛型里還有個挺重要的概念叫 “通配符”&#xff0c;就是那個問號 “?”&#xff0c;很多人第一次見都懵&#xff1a;這玩意兒跟普通泛型有啥區別&#xff1f;為啥有時候非得用它不可&#xff1f;小索奇當初也卡…

EXCEL開發之路(二)跨表交互模擬—仙盟創夢IDE

在車輛租賃行業&#xff0c;數據的高效管理與分析對于企業的運營決策、資源調配及客戶服務優化至關重要。自建 Excel 實現多表統計交互&#xff0c;如同為行業裝上了效能驅動引擎&#xff0c;助力企業在復雜多變的市場環境中穩健前行。一、精準資源管理&#xff0c;優化車輛調配…

醫療AI時代的生物醫學Go編程:高性能計算與精準醫療的案例分析(八)

5.4 性能測試與結果分析 為了評估GoEHRStream的性能,我們設計測試模擬真實的醫院數據流場景,并測量關鍵指標。 5.4.1 實驗環境 硬件: CPU: Intel Xeon E-2288G (8 cores, 16 threads) RAM: 32 GB DDR4 Storage: 512 GB NVMe SSD (用于GoEHRStream和BadgerDB) Network: 1 G…