力扣DAY68 | 熱100 | 尋找兩個正序數組的中位數

前言

困難 ○ 這題搞了3天實在太難了,本質就是每次排除k/2個數,直到找到第k個數。

題目

給定兩個大小分別為?m?和?n?的正序(從小到大)數組?nums1?和?nums2。請你找出并返回這兩個正序數組的?中位數?。

算法的時間復雜度應該為?O(log (m+n))?。

示例 1:

輸入:nums1 = [1,3], nums2 = [2]
輸出:2.00000
解釋:合并數組 = [1,2,3] ,中位數 2

示例 2:

輸入:nums1 = [1,2], nums2 = [3,4]
輸出:2.50000
解釋:合并數組 = [1,2,3,4] ,中位數 (2 + 3) / 2 = 2.5

提示:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -106 <= nums1[i], nums2[i] <= 106

思路

筆者一開始的思路是比較兩個數組的中點排除一半數組,直到有一邊只剩一個數,這樣做的缺點在于判斷條件過多,到最后還要判斷奇偶數,非常麻煩。

官方題解

給定兩個有序數組,要求找到兩個有序數組的中位數,最直觀的思路有以下兩種:

使用歸并的方式,合并兩個有序數組,得到一個大的有序數組。大的有序數組的中間位置的元素,即為中位數。

不需要合并兩個有序數組,只要找到中位數的位置即可。由于兩個數組的長度已知,因此中位數對應的兩個數組的下標之和也是已知的。維護兩個指針,初始時分別指向兩個數組的下標 0 的位置,每次將指向較小值的指針后移一位(如果一個指針已經到達數組末尾,則只需要移動另一個數組的指針),直到到達中位數的位置。

假設兩個有序數組的長度分別為 m 和 n,上述兩種思路的復雜度如何?

第一種思路的時間復雜度是 O(m+n),空間復雜度是 O(m+n)。第二種思路雖然可以將空間復雜度降到 O(1),但是時間復雜度仍是 O(m+n)。

如何把時間復雜度降低到 O(log(m+n)) 呢?如果對時間復雜度的要求有 log,通常都需要用到二分查找,這道題也可以通過二分查找實現。

根據中位數的定義,當 m+n 是奇數時,中位數是兩個有序數組中的第 (m+n)/2 個元素,當 m+n 是偶數時,中位數是兩個有序數組中的第 (m+n)/2 個元素和第 (m+n)/2+1 個元素的平均值。因此,這道題可以轉化成尋找兩個有序數組中的第 k 小的數,其中 k 為 (m+n)/2 或 (m+n)/2+1。

假設兩個有序數組分別是 A 和 B。要找到第 k 個元素,我們可以比較 A[k/2?1] 和 B[k/2?1],其中 / 表示整數除法。由于 A[k/2?1] 和 B[k/2?1] 的前面分別有 A[0..k/2?2] 和 B[0..k/2?2],即 k/2?1 個元素,對于 A[k/2?1] 和 B[k/2?1] 中的較小值,最多只會有 (k/2?1)+(k/2?1)≤k?2 個元素比它小,那么它就不能是第 k 小的數了。

因此我們可以歸納出三種情況:

如果 A[k/2?1]<B[k/2?1],則比 A[k/2?1] 小的數最多只有 A 的前 k/2?1 個數和 B 的前 k/2?1 個數,即比 A[k/2?1] 小的數最多只有 k?2 個,因此 A[k/2?1] 不可能是第 k 個數,A[0] 到 A[k/2?1] 也都不可能是第 k 個數,可以全部排除。

如果 A[k/2?1]>B[k/2?1],則可以排除 B[0] 到 B[k/2?1]。

如果 A[k/2?1]=B[k/2?1],則可以歸入第一種情況處理。

可以看到,比較 A[k/2?1] 和 B[k/2?1] 之后,可以排除 k/2 個不可能是第 k 小的數,查找范圍縮小了一半。同時,我們將在排除后的新數組上繼續進行二分查找,并且根據我們排除數的個數,減少 k 的值,這是因為我們排除的數都不大于第 k 小的數。

有以下三種情況需要特殊處理:

如果 A[k/2?1] 或者 B[k/2?1] 越界,那么我們可以選取對應數組中的最后一個元素。在這種情況下,我們必須根據排除數的個數減少 k 的值,而不能直接將 k 減去 k/2。

如果一個數組為空,說明該數組中的所有元素都被排除,我們可以直接返回另一個數組中第 k 小的元素。

如果 k=1,我們只要返回兩個數組首元素的最小值即可。

class Solution {
public:double findk(vector<int>& nums1, vector<int>& nums2, int k){double ans;int m = nums1.size();int n = nums2.size();int index1 = 0, index2 = 0; //區間起點while(true){//一個數組已完全排除if (index1 == m)return nums2[index2 + k - 1];if (index2 == n)return nums1[index1 + k - 1];//剩余一個要排除,排除大的返回小的if (k == 1)return min(nums1[index1], nums2[index2]);//區間終點,k/2-1是區間長度,如果該長度超過數組長度,直接取數組最后一個值int newindex1 = min(index1 + k / 2 - 1, m - 1);int newindex2 = min(index2 + k / 2 - 1, n - 1);//區間終點值,也就是要比較的值int point1 = nums1[newindex1];int point2 = nums2[newindex2];//終點值小的一邊包括終點全被排除//更新k,更新小的一邊的起點坐標(上一個終點的下一位)//等號在哪里不影響結果if (point1 <= point2){k -= newindex1 - index1 + 1;index1 = newindex1 + 1;}else{k -= newindex2 - index2 + 1;index2 = newindex2 + 1;}}return ans;}double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int m = nums1.size();int n = nums2.size();double ans;if ((m+n)%2 == 0){ans = (findk(nums1, nums2, (m+n)/2)+findk(nums1, nums2, (m+n)/2+1))/2;}else{ans = findk(nums1, nums2, (m+n)/2+1);}return ans;}
};

心得

結束二分專題,這個題目需要非常強的邏輯思維,否則很容易被繞進去。再回顧下解法:奇數找中間數,偶數找中間兩個數除2。定義一個函數找兩個數組的第k位數,定義初始起點為0,數組長度為k/2-1(保證每次排除不會把k排走),進入循環后計算數組終點:起點+長度,如果超過整個數組長度則取最后一位。比較兩個區間終點,把小的一邊排除,循環比較。直到一邊被完全排除,直接返回另一個數組的index+k個數;或者k==1,還剩一個數要排除,排除大的,返回小的。做這個專題的時候太過急躁了,過于低估,很多題目沒有好好想清楚邊界情況就框框做,這個是個壞習慣。靜下心來,筆算每個題的思路,具體到抽象再到具體,嚴謹嚴謹再嚴謹!

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

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

相關文章

Linux常見故障:排查思路與錯誤分析指南

引言 當Linux系統"生病"時&#xff0c;它不會說話但卻會通過各種癥狀"求救"&#x1f198;&#xff01;本文將帶你建立系統化的故障排查思維&#xff0c;從磁盤到內存&#xff0c;從網絡到服務&#xff0c;全方位掌握Linux系統的"把脈問診"技巧。…

深度解析:從12306看混合云架構下的高并發系統設計

作為曾參與12306余票查詢系統高并發升級的技術從業者&#xff0c;筆者注意到公眾對于12306底層技術常存在認知盲區。為破解這一迷思&#xff0c;特此分享十年前的架構解密文獻&#xff08;該技術之前名叫 gemfire 現已晉升為Apache頂級項目Geode&#xff0c;代碼庫詳見&#xf…

華為Pura X的智控鍵:讓折疊機體驗更上一層樓的設計

還記得Mate 70系列剛出那會&#xff0c;我體驗了下智控鍵&#xff0c;那時候就覺得這個“把快捷方式做進電源鍵”的交互方式非常驚艷&#xff0c;沒想到在Pura X上&#xff0c;這種便捷體驗感更上了一層樓。 智控鍵&#xff1a;折疊屏手機的天選快捷方式&#xff1f; 傳統折疊…

springboot如何管理多數據源?

靜態多數據源管理 配置多個數據源 :創建多個數據源的配置類,通常使用 @ConfigurationProperties 注解來綁定配置文件中的數據源屬性,并通過 @Bean 注解定義多個 DataSource Bean 。例如: 配置類: @Configuration public class DataSourceConfig {@Bean(name = "prima…

谷歌終止新冠疫情時期結構化數據支持:SEO影響與應對策略

2025年4月&#xff0c;谷歌悄然宣布將于7月31日起停止支持新冠疫情時期的“特殊公告”&#xff08;SpecialAnnouncement&#xff09;結構化數據。這一舉措標志著谷歌正式結束一項在疫情期間推出的實驗性功能&#xff0c;對依賴該結構化數據的網站管理員和SEO從業者來說&#xf…

常見游戲引擎介紹與對比

Unreal Engine (UE4/UE5) 主語言&#xff1a;C Unreal Engine 主要使用 C 作為開發語言。C 提供了高性能的底層控制&#xff0c;適用于需要精細調優的 AAA 級游戲。C 在 Unreal 中用于開發核心游戲邏輯、物理引擎等性能要求較高的部分。 腳本語言&#xff1a;藍圖&#xff08;B…

【C++】繼承----下篇

文章目錄 前言一、實現一個不能繼承的類二、友元與繼承三、繼承與靜態成員四、多繼承以及菱形繼承問題1.繼承模型&#xff1a;2.菱形繼承的問題3.虛擬繼承解決數據冗余和二義性的原理4.虛擬繼承的原理 五、繼承的總結和反思1.繼承和組合 總結 前言 各位好呀!今天呢我們接著講繼…

洛谷 B3647:【模板】Floyd 算法

【題目來源】 https://www.luogu.com.cn/problem/B3647 【題目描述】 給出一張由 n 個點 m 條邊組成的無向圖。 求出所有點對 (i,j) 之間的最短路徑。 【輸入格式】 第一行為兩個整數 n&#xff0c;m&#xff0c;分別代表點的個數和邊的條數。 接下來 m 行&#xff0c;每行三…

netlist

在電子設計自動化&#xff08;EDA&#xff09;中&#xff0c;網表&#xff08;Netlist&#xff09; 是描述電路設計連接關系的核心數據結構&#xff0c;本質上是電路元件&#xff08;如邏輯門、晶體管、模塊&#xff09;及其互連關系的 文本化或結構化表示。它是從抽象設計&…

Cadence學習筆記之---原理圖設計基本操作

目錄 01 | 引 言 02 | 環境描述 03 | 原理圖工具介紹 04 | 原理圖設計基本操作 05 | 生成頁間引用 06 | 元件自動編號 07 | 結 尾 01 | 引 言 書接上回&#xff0c;在前文中講述了怎樣制作常用的庫元件&#xff0c;如電阻、二極管&#xff0c;IC器件&#xff0c;以及怎…

【華為HCIP | 華為數通工程師】821—多選解析—第十七頁

多選835、IS-IS協議所使用的NSAP地址主要由哪幾個部分構成? A、AREA ID B、SEL C、DSCp D、SYSTEM ID 解析:NSAP地址:網絡服務訪問點(Network Service Access Point)是 OSI 協議中用于定位資源的地址。NSAP 的地址結構如圖所示,它由 IDP(Initial Domain …

Linux系統中命令設定臨時IP

1.查看ip ---ifconfig 進入指定的網絡接口 ifconfig ens160 建立服務器臨時IP ifconfig ens160 ip地址 network 系統進行重啟后&#xff0c;臨時IP將會消失 ip address add ip地址 dev 服務器 ---添加臨時ip ip address delete ip地址 dev 服務器 ---刪除臨時ip 設置ip&a…

深度學習之卷積神經網絡入門

一、引言 在深度學習蓬勃發展的今天&#xff0c;卷積神經網絡&#xff08;Convolutional Neural Network&#xff0c;簡稱 CNN&#xff09;憑借其在圖像識別、計算機視覺等領域的卓越表現&#xff0c;成為了人工智能領域的核心技術之一。從手寫數字識別到復雜的醫學影像分析&a…

使用RabbitMQ實現判題功能

這次主要選用RabbitMQ消息隊列來對判題服務和題目服務解耦&#xff0c;題目服務只需要向消息隊列發送消息&#xff0c;判題服務從消息隊列中取信息去執行判題&#xff0c;然后異步更新數據庫即可。 五一寶寶請快點跑~~~~~ 先回顧一下RabbitMQ &#xff08;1&#xff09;引入依…

HTML5后臺管理界面開發

HTML5后臺管理界面開發 隨著互聯網技術的快速發展&#xff0c;后臺管理系統在各個業務領域中扮演著越來越重要的角色。它不僅幫助企業管理數據、用戶和業務流程&#xff0c;也為決策提供了依據。本文將介紹如何使用HTML5開發一個簡單的后臺管理界面&#xff0c;并結合代碼示例…

Oracle 11g RAC手動打補丁詳細步驟

備份&#xff1a; 節點1&#xff1a; root用戶備份GI_home tar cvf Ghome_backup.tar /oracle/grid/crsoracle用戶備份ORACLE_HOME tar cvf ohome_backup.tar $ORACLE_HOME節點2&#xff1a; root用戶備份GI_home tar cvf Ghome_backup.tar /oracle/grid/crsoracle用戶備份…

xfce桌面漢化設置

文章目錄 漢化配置小結 漢化配置 檢查當前語言環境&#xff0c;執行指令locale&#xff0c;如果輸出的 LANG、LC_ALL 等未包含 zh_CN.UTF-8&#xff0c;需要設置中文環境。 安裝中文語言包 sudo apt update sudo apt install language-pack-zh-hans language-pack-zh-hant設置…

如何在IDEA中高效使用Test注解進行單元測試?

在軟件開發過程中&#xff0c;單元測試是保證代碼質量的重要手段之一。而IntelliJ IDEA作為一款強大的Java開發工具&#xff0c;提供了豐富的功能來支持JUnit測試&#xff0c;尤其是通過Test注解可以快速編寫和運行單元測試。那么&#xff0c;如何在IDEA中高效使用Test注解進行…

Linux 路由

Linux路由表 一&#xff1a;查看路由二&#xff1a;添加路由三&#xff1a;刪除路由四&#xff1a;路由測試五&#xff1a;路由選擇機制1.路由表2.路由匹配機制3.策略路由 示例1.多網卡分流2.VPN分流3.雙默認路由負載均衡 一&#xff1a;查看路由 # 查看 main 表 ip route sho…

x-cmd install | brows - 終端里的 GitHub Releases 瀏覽器,告別繁瑣下載!

目錄 核心功能與優勢安裝適用場景 還在為尋找 GitHub 項目的特定 Release 版本而苦惱嗎&#xff1f;還在網頁上翻來覆去地查找下載鏈接嗎&#xff1f;現在&#xff0c;有了 brows&#xff0c;一切都將變得簡單高效&#xff01; brows 是一款專為終端設計的 GitHub Releases 瀏覽…