算法日記---二分查找

目錄

前言

一、二分查找

1.思想

2.簡單二分

3.優點

4.局限性

二、模板

1.基本模板

2.簡單例題(LeetCode)

4.有重復元素的二分

5.0-1問題

總結


前言

本文通過講解簡單的二分查找配合leetcode例題對二分查找本質、模板進行了基礎的總結


提示:以下是本篇文章正文內容,下面案例可供參考

一、二分查找

1.思想

二分查找本質是折半查找思想,每一輪查找的范圍是上一輪的一半,每次查找比較中間元素的值和目標值的大小。比較結論決定去哪一邊作為下一輪的查找范圍,循環直到查找范圍為空。

2.簡單二分

簡單二分指的是數組不包含重復的元素,重點關注每次判邊的邏輯。

3.優點

速度快 O(logn)且不需要額外的空間

4.局限性

  • 有序:需要保證每次折半都有意義
  • 數組:數組尋址的復雜度是 O (1)。如果是用鏈表存儲一串數,二分查找是無意義的。鏈表的尋址是 O (n)。

二、模板

1.基本模板

二分查找的模板很多樣,開閉的條件不同,判斷的條件也不同

最本質的問題是當前判斷結束后,下一次要取左半邊還是右半邊縮小區間的條件是什么?判斷的條件是什么?

注意:

  1. left<=right:實際進入循環時,left和right只向的元素不會進行if條件判斷。比如left=right時,加此等號,才會對二者所指元素進行判斷。否則不會。
  2. mid =(left+right)>>>1:因為java會把最高位看成符號位,如果兩個數過大,可能會導致數據溢出問題。我們需要通過無符號右移運算符來避免這種問題。還有一種寫法是mid=left+(right-left)/2
  3. 更新left和right,避免死循環
public static int binarySerach(int[] a,int target){int left=0;int right=a.length-1;while(left<=right){int mid=(left+right)>>>1;if(target<a[mid]){//目標數在左邊right=mid-1;}else if(a[mid]<target){//目標書在右邊left=mid+1;}else{return mid;}}return -1;
}

2.簡單例題(LeetCode)

1.704. 二分查找(基本簡單)

class Solution {public int search(int[] nums, int target) {int left=0;int right=nums.length-1;while(left<=right){int mid=(left+right)>>>1;if(nums[mid]<target){left=mid+1;}else if(nums[mid]>target){right=mid-1;}else{return mid;}}return -1;}
}

2.744.尋找比目標字母大的最小字母

class Solution {public char nextGreatestLetter(char[] letters, char target) {int left=0;int right=letters.length-1;while(left<=right){int mid=(left+right)>>>1;if(letters[mid]<=target){left=mid+1;}else{right=mid-1;}}return left<letters.length?letters[left]:letters[0];}
}

3.74. 搜索二維矩陣

class Solution {public boolean searchMatrix(int[][] matrix, int target) {int left=0;//使用m*n將二維轉為一維int m=matrix[0].length;int n=matrix.length;int right=m*n-1;while(left<=right){int mid=(left+right)>>>1;int x=matrix[mid/m][mid%m];//把mid元素轉換回原二維矩陣的位置if(x==target){return true;}else if(x>target){right=mid-1;}else{left=mid+1;}}return false;}
}

4.162. 尋找峰值

此題究其本質依然是二分查找,我們需要根據題目重要條件進行理解

“你可以假設?nums[-1] = nums[n] = -∞?。”

以下做法需要注意邊界情況的判斷

class Solution {public int findPeakElement(int[] nums) {int n = nums.length;if (n == 1) {return 0;}int left = 0, right = n - 1;while (left <= right) {int mid = left + (right - left) / 2;// 邊界情況判斷:數組第一個元素是峰值(只有它自己,或者比下一個大)if (mid == 0) {if (nums[mid] > nums[mid + 1]) {return mid;}}// 邊界情況判斷:數組最后一個元素是峰值(只有它自己,或者比前一個大)else if (mid == n - 1) {if (nums[mid] > nums[mid - 1]) {return mid;}}// 中間位置是峰值(比左右都大)else if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) {return mid;}// 判斷峰值在左側還是右側if (nums[mid] < nums[mid + 1]) {// 右側有上升趨勢,峰值在右側left = mid + 1;} else if (nums[mid] < nums[mid - 1]) {// 左側有上升趨勢,峰值在左側right = mid - 1;}}// 理論上不會走到這里,因為題目保證有解return -1;
}}

題解中的做法是無需單獨判斷邊界情況的,也沒有主動對mid元素與左右兩元素進行比較

因為左右邊界都是負無窮,找到往遞增的一邊方向找就一定能找到峰值(圖中白圈內區域)。這就代表著?只要數組中存在一個元素比相鄰元素大,那么沿著它一定可以找到一個峰值。

特點:一分為二后,一側是有序數組,另一側是循環數組。

根據這個特點,先判斷有序數組、循環數組分別在哪一側,再判斷 target 在有序數組 還是 循環數組中

判斷方法是讓 target 和有序數組的首尾做比較,看是否在有序數組中。

1.?3. 搜索旋轉排序數組

class Solution {public int search(int[] nums, int target) {int left=0;int right=nums.length-1;while(left<=right){int mid=(left+right)>>>1;if(nums[mid]==target){return mid;}//左半部分有序if(nums[left]<=nums[mid]){//目標值在左半部分區間內if(nums[left]<=target && target<nums[mid]){right=mid-1;}else{left=mid+1;//縮小范圍到右半部分區間}}// 右半部分是有序的else {// 目標值在右半部分有序區間內if (nums[mid] < target && target <= nums[right]) {left = mid + 1;} else {right = mid - 1;//縮小范圍到左半部分區間}}}return -1;}}

2.153. 尋找旋轉排序數組中的最小值

不多說了,都在注解里:

最主要的還是需要判斷目標值到底是在mid的左邊還是右邊,才能進行下一步二分。而判斷依據就是根據兩端遞增區間的特性將nums[mid]和nums[right]進行比較。這也就是開篇說的判斷取左半段還是右半段最重要的條件。

class Solution {public int findMin(int[] nums) {int left=0;int right=nums.length-1;while(left<=right){int mid=(left+right)>>>1;//首先由題可知,數組一定被分為了左右兩個遞增區間(或者沒分,也就是0次旋轉),且第一段所有元素大于第二段所有元素//需要比較nums[mid]和nums[right]的關系。//如果<=,意味著nums[mid]一定處于第二個遞增區間,最小值要么是該元素,要么就在該元素左側//如果>,意味著nums[mid]處于第一個遞增區間。最小值一定在該元素右側if(nums[mid]>nums[right]){//mid處于左半段left=mid+1;}else{//mid處于右半段if(mid==0||nums[mid]<=nums[mid-1]){//mid就是最小值,注意mid=0時索引越界問題return nums[mid];}else{//mid處于右半段,但最小值在mid的左邊right=mid-1;}}}return -1;}
}

4.有重復元素的二分

通常要求找出第一個目標元素或是最后一個目標元素

存在重復元素的二分查找,無非就是多加了一個判斷,判斷是否為第一個/最后一個。

以查詢第一個目標元素為例,判斷條件就是看mid-1是否等于target,如果不是,那么mid就是我要

找的數了。這依然是二分關鍵。

public class BinarySearch {public static int binarySearch(int[] nums, int target) {int left = 0;int right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] < target) {left = mid + 1;} else if (nums[mid] > target) {right = mid - 1;} else {// 當找到目標值時,判斷是否是第一個出現的位置if (mid == 0 || nums[mid - 1] != target) {//是第一個元素,注意索引越界問題。return mid;} else {right = mid - 1;}
//以下為找最后一個目標元素的判斷條件
//if (mid == nums.length-1 || nums[mid+1]!=target){
//}else{
// left=mid+1;}}}return -1;}public static void main(String[] args) {int[] nums = {1, 3, 8, 8, 8, 9};int target = 8;int result = binarySearch(nums, target);System.out.println("第一個目標值 " + target + " 的索引是: " + result);}
}

5.0-1問題

點到為止,下期再見。


總結

本文對二分查找進行簡單講解,還有比較常見的二分查找應用“0-1問題”留著下期講解。

二分的模板多種多樣,但究其本質最重要的還是如何判斷下一次二分的區間,取左邊還是取右邊。這個就是需要根據不同題目思考的點了

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

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

相關文章

Level Set(水平集)算法——形象化講解

目錄 維度一&#xff1a;核心思想與比喻&#xff08;它像什么&#xff1f;&#xff09; 維度二&#xff1a;要解決什么問題&#xff1f;&#xff08;它能干嘛&#xff1f;有什么用&#xff1f;&#xff09; 維度三&#xff1a;工作原理&#xff08;它是怎么做到的&#xff1…

DDoS 攻防“軍備競賽”的幕后

談到 DDoS&#xff08;分布式拒絕服務攻擊&#xff09;&#xff0c;很多人會想到“黑客租用肉雞發流量&#xff0c;網站直接崩”。但事實上&#xff0c;如今的 DDoS 攻防早已變成一場 軍備競賽。攻擊者的武器越來越“工業化”&#xff1a;僵尸網絡商品化&#xff1a;黑市上&…

如何用 Rust 重寫 SQLite 數據庫(二):是否有市場空間?

用 Rust 實現一個類似 SQLite 的嵌入式數據庫非常有意義&#xff0c;但需要結合具體目標和場景來評估其價值。以下從技術、生態、市場需求和個人成長等多個維度展開分析&#xff0c;并給出結論。一、技術價值&#xff1a;Rust 與數據庫的天然契合 SQLite 作為全球裝機量最大的數…

【Web】ImaginaryCTF 2025 wp

目錄 imaginary-notes certificate codenames-1 passwordless pearl imaginary-notes I made a new note taking app using Supabase! Its so secure, I put my flag as the password to the "admin" account. I even put my anonymous key somewhere in the si…

oracel如何找到外鍵子表

要找到導致外鍵約束沖突的子表&#xff08;即包含"child record"的表&#xff09;&#xff0c;可以通過以下SQL查詢在Oracle數據庫中定位&#xff1a;1. 查詢約束基本信息&#xff08;確定父表和子表&#xff09;SELECT owner, constraint_name, table_name AS child…

智源研究院新研究:突破物理世界智能邊界的RoboBrain 2.0,將重構具身AI能力天花板

當你對著家用機器人說"把杯子放在筆筒和鍵盤之間&#xff0c;對齊杯身logo"時&#xff0c;它能精準理解空間關系并執行動作&#xff1b;當多臺機器人在超市協作補貨時&#xff0c;它們能自主規劃軌跡、避免沖突并完成長周期任務——這些曾經出現在科幻電影中的場景&a…

【2025】Office核心組件Microsoft word,Excel,PowerPoint詳細使用指南

Office 核心組件使用指南 Microsoft Word 文字處理 Word主要用于創建和編輯文檔&#xff0c;如信件、報告、論文等。 2025Office&#x1f517; 1. 界面認識 快速訪問工具欄&#xff1a;位于左上角&#xff0c;可自定義保存、撤銷、恢復等常用命令。功能區&#xff1a;頂部…

【模型訓練篇】VeRL的使用 - RL(PPO)與源碼

繼續學習字節家的VeRL&#xff0c;今天來看看VeRL的RL&#xff0c;是VeRL系列的第三篇文章&#xff08;話說近期好多大事兒&#xff0c;我司發布了Longcat、韓立結嬰、阿里周五發布了QWen-Next都是好東西啊&#xff0c;學不過來了damn&#xff09; 底層分布式能力基礎Ray&…

QML Charts組件之折線圖的鼠標交互

目錄前言相關系列代碼示例詳解&#xff08;LineSeriesDemo3.qml&#xff09;功能概覽運行效果代碼說明工程下載參考前言 接上文&#xff08;QML Charts組件之折線圖的基礎屬性&#xff09;&#xff0c;本文將重點介紹LineSeries的鼠標交互&#xff0c;包括&#xff1a;鼠標拖拽…

二值信號量——學習筆記12

本文是筆者在學習 正點原子官方 的《【正點原子】手把手教你學FreeRTOS實時系統》系列視頻時整理的筆記。 視頻講解清晰透徹&#xff0c;非常感謝UP主的無私奉獻&#xff01;原課程鏈接如下&#xff1a; &#x1f449; B站視頻鏈接&#xff1a;??????【正點原子】手把手教…

裸機開發 時鐘配置,EPIT

1.概念時鐘(clock)&#xff1a;在電子系統中是一個產生穩定、周期性振蕩信號的電路或組件。這個信號像節拍器或心跳一樣&#xff0c;為數字電路中的各種操作提供同步時序基準。PLL&#xff08;phase locked loop&#xff09;鎖相環電路: 倍頻PFD&#xff08;phase fractional P…

Linux-文本三劍客(grep、sed、awk)

Linux-文本三劍客前言一、grep二、sed三、awk模式 -- 正則表達式關系表達式、運算符表達模式匹配表達式動作 輸出流程控制參數傳遞&#xff0c;awk接受外部變量統計數組的使用分組統計練習常用內置函數前言 grep、sed、awk 被稱為 “文本三劍客”&#xff0c;它們是處理文本文…

主流反爬蟲、反作弊防護與風控對抗手段

文章目錄1. 寫在前面2. 指紋檢測3. 行為驗證3. 加固防護4. 鏈路檢測5. 風控埋點6. 游客注冊7. 數據防護8. 賬號權重9. 反調阻斷【&#x1f3e0;作者主頁】&#xff1a;吳秋霖 【&#x1f4bc;作者介紹】&#xff1a;擅長爬蟲與JS加密逆向分析&#xff01;Python領域優質創作者、…

金蝶云星空插件開發記錄(一)

實現目的&#xff1a;新增供應商保存后&#xff0c;觸發釘釘審批流程&#xff0c;并根據釘釘審批結果回寫是否合格供應商。實現思路&#xff1a;通過BOS平臺供在應商管理界面新增兩個復選框字段&#xff1a;是否釘釘審批、是否合格供應商&#xff0c;若在新建供應商檔案時勾選是…

企業跨區域組網新解:SD-WAN技術打造安全穩定網絡體系

前言在數字化浪潮席卷全球的今天&#xff0c;企業跨區域網絡互聯已成為支撐業務發展的關鍵基礎設施。傳統MPLS專線雖性能穩定&#xff0c;但高昂成本和漫長部署周期令眾多企業望而卻步。SD-WAN技術的出現&#xff0c;正以其智能、靈活和成本效益的優勢&#xff0c;重塑企業組網…

Docker 容器化

引言在解釋docker是什么之前&#xff0c;我們首先應該先了解的是容器化的概念。什么是容器&#xff1f;就是一個沙箱&#xff0c;在這個沙箱中涵蓋了特定應用運行的一切依賴的內容。但他不是一個操作系統&#xff0c;且和底層的操作系統是隔離的。什么是容器化&#xff1f;容器…

LeetCode刷題——hot 100(3)

題目1&#xff1a;矩陣置零題目&#xff1a;問題分析&#xff1a;使用兩個布爾數組來分別記錄哪行哪列出現了0&#xff0c;當出現0的行和列&#xff0c;對應的布爾數組值置為true。再次遍歷數組&#xff0c;當出現行數組和列數組中的值為true&#xff0c;則對應的原數組的值置為…

Ajax-day2(圖書管理)-渲染列表

本篇筆記素材來自“黑馬程序員” 渲染列表圖書管理一、獲取數據二、渲染數據完整代碼圖書管理 Bootstrap 框架渲染列表&#xff08;查&#xff09;新增圖書&#xff08;增&#xff09;刪除圖書&#xff08;刪&#xff09;編輯圖書&#xff08;改&#xff09; 自己的圖書數據&a…

MOS管的電路

MOS管的三極都會存在以下三個電容&#xff0c;分別是&#xff1a;Cgs,Cgd,Cds 輸入電容CissCgsCgd 輸出電容CossCgdCds 反向傳輸電容CrssCgd&#xff0c;也叫米勒電容 然而&#xff0c;這三個等效電容是構成串并聯組合關系&#xff0c;他們并不是獨立的&#xff0c;而是相互…

STM32_05_時鐘樹

時鐘 d用來輸入數據&#xff0c;CLK就是我們的時鐘&#xff0c;CPU1s中72000000HZ個時鐘周期STM32的時鐘樹鎖相環HSE時鐘源HSI時鐘源LSE時鐘源LSI時鐘源SystemInit函數SetSysClock函數SetSysClockTo72函數SystemInit()后時鐘頻率大小總結RCC標準庫函數定義變量a&…