面試經典150題——用最少數量的箭引爆氣球

"The only person you are destined to become is the person you decide to be." - Ralph Waldo Emerson

scenery of mountain

1. 題目描述

2. ?題目分析與解析

這個題目開始讀題的時候是有點不好理解題意的,因此我先做個圖讓大家對于題意有更好更直觀的理解再來分析題目。

比如對于這個測試用例:

image-20240301092542335

實際上points就是氣球的寬度,可視化如下:

image-20240301093354544

而題目要求的就是引爆所有氣球所必須射出的 最小 弓箭數 ,對于上述情況,那么就需要以下紅色的兩支箭:

image-20240301093746553

其中虛線框就是表示兩支箭的可以橫向移動的范圍。第一支箭從【2,6】都可以射出從而擊破兩個氣球,第二支箭從【10,12】都可以射出擊破剩下的兩個氣球。

2.1 思路一

可以看出本題的實質就是在找能夠涵蓋所有氣球的最小交集個數。那么我們首先應該想到的是排序,經過排序后,然后遍歷每一個區間,查看當前區間能夠附帶擊破的氣球的個數,比如如下圖:

image-20240301094647448

首先遍歷第一個區間【1,6】,查看每一個位置能夠附帶擊破的氣球的個數,在數字1的位置,發現只能附帶擊破自己本身1個氣球,在【2,4】發現能擊破兩個,但是在【5,6】(因為等于5就可以擊破藍色氣球:滿足 ?xstart ≤ x ≤ x``end,則該氣球會被 引爆 ),所以我們肯定得將箭設置成能擊破最多個數氣球的位置,也就是擊破三個氣球,然后移除這些已經被擊破的氣球,繼續尋找下一個區間,以此循環,直到沒有剩余的氣球。

代碼思路

  1. 初始化兩個變量,一個用來統計刪除區間的位置,一個用來統計結果

  2. 按照區間的開始位置進行從小到大排序

  3. 從最小的區間開始,查看每一個數字射出箭能夠擊破的最大氣球數以及擊破氣球的位置

    • 也就是判斷某個數字能否被某些區間所包含,即是否大于等于區間的最小值且小于等于區間的最大值

    • 找到最多的能被包含的位置及相關區間,刪除這些區間

  4. 從當前集合中取出下一個最小區間重復以上步驟直到集合為空

  5. 返回結果

但是理所當然的報了超時,因為我們嘗試去遍歷了每一個可能射出箭的位置

image-20240301103046577

2.2 思路二

根據上面的思路,其實我們的本質就是找每個區間和其余區間的最大交集個數。

而因為如果我們按照區間的開始位置從小到大進行排序,那么我們就需要根據下一個區間的開始位置是否小于等于當前遍歷區間的結束位置,如下,假設現在遍歷第一個藍色區間:

image-20240301111734803

我們發現綠色的開始位置小于藍色氣球的結束位置,所以我們就可以斷定他們倆有交集(因為左端點已經經過排序了的)。然后再看下一個區間也就是黃色氣球,發現還是有交集,那么我們是不是就可以斷定這一支箭一定就可以一串三呢?

答案是否定的,雖然對于上述圖中是可以從x=6射出一只箭來打破這三個氣球,然后從剩余氣球的第一個位置繼續遍歷,但是如果是如下的情況呢?

image-20240301112249384

這時可以發現,雖然遍歷的第一個藍色氣球和黃色綠色兩個氣球都相交,但是我們并不能用一只箭將他們全部射破,因為綠色和黃色并不像上面開始的圖中給出的示例一樣能夠在 x=6處相交。

所以此時要注意,在判斷完畢第一個藍色氣球和綠色氣球之后,我們需要把結束位置更新,更新為 6,因為綠色氣球必須要一只 x<=6 的箭來射穿它。

這時如果結束位置是6,我們再來判斷黃色氣球的開始位置和當前區間也就是 【1,6】是否相交,發現是不可以的,就可以斷定需要一只箭來射穿前兩個氣球。然后我們再從黃色氣球開始向后按照之前的步驟繼續發出箭。

所以核心點就是: 我們一定要把結束位置更新為走過的氣球中的最小值

所以根據以上性質,我們可以給出以下代碼思路:

代碼思路:

  1. 對氣球區間進行升序排序

  2. 遍歷每一個區間,查看當前區間的下一個區間的開始位置是否小于等于當前區間的結束位置

    • 如果滿足,就將遍歷的區間索引++,也就相當于移除了這個區間,然后更新右端點為兩者的最小值。

  3. 如果走到某一個區間發現不滿足上述條件,那么直接射出一只箭,然后遍歷剩下的區間

小錯誤排查

但是按照以上思路求解發現了一個問題,就是對于該測試用例:

image-20240301115301619

發現解答錯誤,然后我debug了一下,發現按照從小到大排序是這樣的:

image-20240301115243116

通過排查了一番,找到了原因如下:

在排序時,我是用如下代碼:

 ? ? ? ?//1. 對氣球區間進行升序排序Arrays.sort(points, (o1, o2) -> o1[0] - o2[0]);

該代碼片段是使用一個自定義比較器對二維數組points進行排序的Java代碼。這個比較器是一個lambda表達式,它比較兩個區間的開始點o1[0]o2[0]

這個比較器通過計算兩個開始點的差值o1[0] - o2[0]來決定排序順序。在Java中,Comparator接口期望的返回值為負數、零或正數,分別表示第一個參數小于、等于或大于第二個參數。

但是因為測試用例中整數值接近Integer類型的極限,所以這個比較器的計算可能會導致整數溢出:

  • 如果o1[0]是一個非常大的正數,而o2[0]是一個負數,那么理論上o1[0]應該大于o2[0]

  • 但是如果o1[0]o2[0]的差值大于Integer.MAX_VALUE(即2147483647),那么計算結果將會溢出,導致返回一個負值。

  • 這會使得排序函數錯誤地認為o1[0]小于o2[0]

為了避免整數溢出,那么應該使用Integer.compare()方法來比較兩個整數,它能正確處理溢出的情況。下面是修改后的代碼:

Arrays.sort(points, (o1, o2) -> Integer.compare(o1[0], o2[0]));

使用Integer.compare()方法可以確保即使是接近整數極限的值,比較操作也會正確執行,返回正確的排序順序。

經過修改后完美解決!

2.3 思路三

在思路二中,實際上是對思路一的優化,減少了一些不必要的判斷,思路二需要不斷更新右邊界來確保正確的射出箭。那么我們可不可以不更新右邊界呢?

因為我們之所以不斷更新右邊界,就是想知道在哪個位置之前必須得射出一只箭,這是必須依賴于右邊界的值的。那我們是不是可以根據右邊界從小到大進行排序,以每一個當前區間的右邊界作為指標,判斷其余區間是否能和它相交?

這樣其實每一個右邊界就是一次極限,必須射出一只箭的極限,因為如果到了右邊界還不射出,那么當前這個氣球就無法被擊破了。所以根據以上思路,我們可以對右邊界從小到大排序,得出以下:

代碼思路:

假設給定的區間集合中的每個區間表示為一個點對[xstart, xend]

  1. 按照xend排序:首先將所有區間按照xend的值從小到大排序,這樣可以確保我們每次選擇的區間都是最先結束的。

  2. 選擇區間:從排序后的區間列表中選擇第一個區間,這個區間的xend將覆蓋第一個坐標點。這將是我們選擇的第一個區間。

  3. 覆蓋剩余的點:然后遍歷剩下的點,對于每個點,如果它沒有被當前已經選擇的區間集合中的任何一個區間覆蓋,那么我們就選擇下一個區間。我們選擇的區間是排序后列表中第一個xstart小于或等于該點坐標的區間。

  4. 重復:重復上述過程,直到所有的點都被覆蓋。

  5. 計數:在上述過程中,我們每選擇一個區間就將計數器加一,最后的計數器的值就是最少需要的區間數。

3. 代碼實現

3.1 思路一

image-20240301103352922

image-20240301103400613

3.2 思路二

image-20240301120054936

image-20240301120103742

3.3 思路三

image-20240301121019506

image-20240301121004056

4. 相關復雜度分析

解法一

  • 時間復雜度:O(n^2),最壞情況下,每個區間都會與每個箭進行比較。

  • 空間復雜度:O(1),沒有使用額外的空間,除了幾個變量以外。

解法二

  • 時間復雜度:O(n log n),排序的時間復雜度是O(n log n),遍歷區間的時間復雜度是O(n),因此總的時間復雜度是O(n log n)。

  • 空間復雜度:O(1),排序可能需要O(log n)的空間復雜度(如果使用的是快速排序),但通常我們認為這是排序操作的內在空間使用,并且不會超過O(log n)。

解法三

  • 時間復雜度:O(n log n),與解法二類似,主要的時間消耗在于排序。

  • 空間復雜度:O(1),同樣的理由,主要空間消耗在排序的棧空間上,不會超過O(log n)。

需要注意的是,實際的時間復雜度還取決于使用的排序算法。

在Java中,Arrays.sort()方法對于基本類型使用的是快速排序的變種,對于對象類型使用的是穩定的歸并排序,歸并排序的空間復雜度是O(n)。由于本題中排序的是int[][]類型,即對象類型,所以如果嚴格來說,空間復雜度應為O(n)。但在面試或者實際工作中,如果不是特別強調,我們通常認為這是內置的排序函數的空間復雜度,而不將其計入算法的空間復雜度中。

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

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

相關文章

如何使用Portainer創建Nginx容器并搭建web網站發布至公網可訪問【內網穿透】

文章目錄 前言1. 安裝Portainer1.1 訪問Portainer Web界面 2. 使用Portainer創建Nginx容器3. 將Web靜態站點實現公網訪問4. 配置Web站點公網訪問地址4.1公網訪問Web站點 5. 固定Web靜態站點公網地址6. 固定公網地址訪問Web靜態站點 前言 Portainer是一個開源的Docker輕量級可視…

SQL 常見命令及規范

常見命令 1. 查看當前所有數據庫 show databases; 2. 打開指定的庫 use 庫名 ; 3. 查看當前庫的所有表 show tables; 4. 查看其他庫的所有表 show tables from 庫名 ; 5. 創建表 cerate table 表名 ( 列名 列類型&#xff0c; 列名 列類型&#xff0c; ..... …

基于YOLO家族最新模型YOLOv9開發構建自己的個性化目標檢測系統從零構建模型完整訓練、推理計算超詳細教程【以自建數據酸棗病蟲害檢測為例】

在我前面的系列博文中,對于目標檢測系列的任務寫了很多超詳細的教程,目的是能夠讀完文章即可實現自己完整地去開發構建自己的目標檢測系統,感興趣的話可以自行移步閱讀: 《基于官方YOLOv4-u5【yolov5風格實現】開發構建目標檢測模型超詳細實戰教程【以自建缺陷檢測數據集為…

C# OpenVINO Crack Seg 裂縫分割 裂縫檢測

目錄 效果 模型信息 項目 代碼 數據集 下載 C# OpenVINO Crack Seg 裂縫分割 裂縫檢測 效果 模型信息 Model Properties ------------------------- date&#xff1a;2024-02-29T16:35:48.364242 author&#xff1a;Ultralytics task&#xff1a;segment version&…

去掉WordPress網頁圖片默認鏈接功能

既然是wordpress自動添加的&#xff0c;那么我們在上傳圖片到wordpress后臺多媒體的時候&#xff0c;就可以手動改變鏈接指向或者刪除掉&#xff0c;問題是每次都要這么做很麻煩&#xff0c;更別說有忘記的時候。一次性解決這個問題有兩種方法&#xff0c;一種是No Image Link插…

【生成式AI】ChatGPT原理解析(1/3)- 對ChatGPT的常見誤解

Hung-yi Lee 課件整理 文章目錄 誤解1誤解2ChatGPT真正在做的事情-文字接龍 ChatGPT是在2022年12月7日上線的。 當時試用的感覺十分震撼。 誤解1 我們想讓chatGPT講個笑話&#xff0c;可能會以為它是在一個笑話的集合里面隨機地找一個笑話出來。 我們做一個測試就知道不是這樣…

C# Post數據或文件到指定的服務器進行接收

目錄 應用場景 實現原理 實現代碼 PostAnyWhere類 ashx文件部署 小結 應用場景 不同的接口服務器處理不同的應用&#xff0c;我們會在實際應用中將A服務器的數據提交給B服務器進行數據接收并處理業務。 比如我們想要處理一個OFFICE文件&#xff0c;由用戶上傳到A服務器…

中國汽車電子行業發展現狀分析及投資前景預測報告

全版價格&#xff1a;壹捌零零 報告版本&#xff1a;下單后會更新至最新版本 交貨時間&#xff1a;1-2天 第一章 汽車電子相關概述 1.1 汽車的相關介紹 1.1.1 汽車的概念 我國國家最新標準《汽車和掛車類型的術語和定義》&#xff08;GB/T3730&#xff0e;1—2001&…

基于springboot+vue的貿易行業crm系統

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

Flink分區相關

0、要點 Flink的分區列不會存數據&#xff0c;也就是兩個列有一個分區列&#xff0c;則文件只會存另一個列的數據 1、CreateTable 根據SQL的執行流程&#xff0c;進入TableEnvironmentImpl.executeInternal&#xff0c;createTable分支 } else if (operation instanceof Crea…

Java-nio

一、NIO三大組件 NIO的三大組件分別是Channel&#xff0c;Buffer與Selector Java NIO系統的核心在于&#xff1a;通道(Channel)和緩沖區(Buffer)。通道表示打開到 IO 設備(例如&#xff1a;文件、套接字)的連接。若需要使用 NIO 系統&#xff0c;需要獲取用于連接 IO 設備的通…

Spring的簡單使用及內部實現原理

在現代的Java應用程序開發中&#xff0c;Spring Framework已經成為了不可或缺的工具之一。它提供了一種輕量級的、基于Java的解決方案&#xff0c;用于構建企業級應用程序和服務。本文將介紹Spring的簡單使用方法&#xff0c;并深入探討其內部實現原理。 首先&#xff0c;讓我們…

mysql8.0使用MGR實現高可用

一、三節點MGR集群的安裝部署 1. 安裝準備 準備好下面三臺服務器&#xff1a; IP端口角色192.168.150.213306mgr1192.168.150.223306mgr2192.168.150.233306mgr3 配置hosts解析 # cat >> /etc/hosts << EOF 192.168.150.21 mgr1 192.168.150.22 mgr2 192.168…

Windows環境下的調試器探究——硬件斷點

與軟件斷點與內存斷點不同&#xff0c;硬件斷點不依賴被調試程序&#xff0c;而是依賴于CPU中的調試寄存器。 調試寄存器有7個&#xff0c;分別為Dr0~Dr7。 用戶最多能夠設置4個硬件斷點&#xff0c;這是由于只有Dr0~Dr3用于存儲線性地址。 其中&#xff0c;Dr4和Dr5是保留的…

java中容器繼承體系

首先上圖 源碼解析 打開Collection接口源碼&#xff0c;能夠看到Collection接口是繼承了Iterable接口。 public interface Collection<E> extends Iterable<E> { /** * ...... */ } 以下是Iterable接口源碼及注釋 /** * Implementing this inte…

makefileGDB使用

一、makefile 1、make && makefile makefile帶來的好處就是——自動化編譯&#xff0c;一旦寫好&#xff0c;只需要一個make命令&#xff0c;整個工程完全自動編譯&#xff0c;極大的提高了軟件開發的效率 下面我們通過如下示例來進一步體會它們的作用&#xff1a; ①…

使用 Python 實現一個飛書/微信記賬機器人,酷B了!

Python飛書文檔機器人 今天的主題是&#xff1a;使用Python聯動飛書文檔機器人&#xff0c;實現一個專屬的記賬助手&#xff0c;這篇文章如果對你幫助極大&#xff0c;歡迎你分享給你的朋友、她、他&#xff0c;一起成長。 也歡迎大家留言&#xff0c;說說自己想看什么主題的…

代碼隨想錄第天 78.子集 90.子集II

LeetCode 78 子集 題目描述 給你一個整數數組 nums &#xff0c;數組中的元素 互不相同 。返回該數組所有可能的子集&#xff08;冪集&#xff09;。 解集 不能 包含重復的子集。你可以按 任意順序 返回解集。 示例 1&#xff1a; 輸入&#xff1a;nums [1,2,3] 輸出&…

LeetCode 2581.統計可能的樹根數目:換根DP(樹形DP)

【LetMeFly】2581.統計可能的樹根數目&#xff1a;換根DP(樹形DP) 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/count-number-of-possible-root-nodes/ Alice 有一棵 n 個節點的樹&#xff0c;節點編號為 0 到 n - 1 。樹用一個長度為 n - 1 的二維整數數組 edges…

debian/ubuntu 編譯安裝nginx php

debian/ubuntu 編譯安裝nginx php tar -zxvf nginx-1.9.9.tar.gz apt-get install libpcre3 libpcre3-dev ./configure --prefix/work/nginx-1.9.9 --with-pcre make make install service iptables stop #關閉防火墻, 可能不需要 修改nginx運行用戶為tboqi 抱著log目錄可…