033.搜索旋轉排序數組

題意

整數數組 nums 按升序排列,數組中的值 互不相同

在傳遞給方法之前,nums 在預先未知的某個下標 k(0 <= k < nums.length)上進行了旋轉,使數組變為 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下標 從 0 開始計數)。例如, [0,1,2,4,5,6,7] 在下標 3 處經旋轉后可能變為 [4,5,6,7,0,1,2] 。

給你旋轉后的數組 nums 和一個整數 target,如果 nums 中存在這個目標值 target,則返回它的下標,否則返回 -1 。

你必須設計一個時間復雜度為 O(log n) 的算法解決此問題。

難度

中等

示例

輸入:nums = [4,5,6,7,0,1,2], target = 0
輸出:4輸入:nums = [4,5,6,7,0,1,2], target = 3
輸出:-1

分析 1

這道題咋眼一看,有點繞,給一個旋轉后的數組,和一個目標值,并要求我們找到這個目標值的下標。

但稍微分析一下就知道,就是在一個數組當中查找一個目標值,如果不考慮時間復雜度的話,我們可以直接遍歷一遍,找到就返回下標,找不到就返回-1。

超級簡單:

class Solution {public int search(int[] nums, int target) {for(int i = 0;i < nums.length;i++){if(nums[i] == target)return i;}return -1;}
}

來看一下效率:

效率不錯,但要時間復雜度為對數級別。那就要考慮別的算法

分析 2

我們知道,在一個有序的數組里面去判斷一個數是否存在,可以利用二分查找,時間復雜度剛好就是$O(\log{n})$。

但這道題只是部分有序(因為旋轉了),該怎么去判斷呢?

閉上眼,想一下。

從任意位置將這個部分有序的數組分開,那么分開之后的兩部分必然有一部分是有序的!

比如:

nums = [4,5,6,7,0,1,2]      
nums = [4] [5,6,7,0,1,2]	breakPos = 1
nums = [4,5] [6,7,0,1,2]    breakPos = 2
nums = [4,5,6] [7,0,1,2]    breakPos = 3
nums = [4,5,6,7] [0,1,2]    breakPos = 4
nums = [4,5,6,7,0] [1,2]    breakPos = 5
nums = [4,5,6,7,0,1] [2]    breakPos = 6

果然,至少有一部分是有序的。那我們是不是就可以從有序的部分當中去尋找 target 呢?

可以是可以,但時間復雜度并不是 $O(\log{n})$,還要加上 breakPos 分割后無序的部分,合起來就是$O(n + \log{n})$,顯然也不符合題目的要求。

考慮下面的思路:

  • 如果[lef,breakPos - 1]是有序的,而且nums[lef] <= target && target < nums[breakPos],那么答案肯定在[lef, breakPos - 1],直接調整上界rig到breakPos - 1。
  • 如果[breakPos,rig]是有序的,而且nums[breakPos] < target && target <= nums[rig],那么答案肯定在[breakPos,rig]中,調整下界lef到breakPos即可。

也就是說,我們通過判斷有序的部分,來決定下一步的查找范圍。

  • 只有在有序區間內才可以通過區間兩端的數值判斷 target 是否在其中。
  • 判斷有序區間還是亂序區間:left <= right 是順序區間,否則亂序區間。
  • 每次二分至少存在一個有序區間。
class Solution {public int search(int[] nums, int target) {int siz = nums.length; // 數組長度int lef = 0, rig = siz - 1; // 初始化左右指針while (lef <= rig) { // 當左指針小于等于右指針時進行循環int mid = (lef + rig) >> 1; // 計算中間索引,使用右移運算符相當于除以 2if (nums[mid] == target) // 如果中間元素等于目標值,返回中間索引return mid;if (nums[0] <= nums[mid]) { // 如果左半部分有序if (nums[0] <= target && target < nums[mid]) // 如果目標值在左半部分范圍內rig = mid - 1; // 移動右指針elselef = mid + 1; // 否則移動左指針} else { // 右半部分有序if (nums[mid] < target && target <= nums[siz - 1]) //如果目標值在右半部分范圍內lef = mid + 1; // 移動左指針elserig = mid - 1; // 否則移動右指針}}return -1; // 如果未找到目標值,返回 -1}
}

我們來分析一下代碼的關鍵部分:

第一步,初始化

  • siz:數組長度。
  • lef 和 rig:左右指針,分別初始化為數組的第一個和最后一個索引。

第二步,二分查找

計算中間索引 mid;如果 nums[mid] 等于目標值 target,直接返回 mid。

檢查數組的左半部分是否有序(nums[0] <= nums[mid])。

如果左半部分有序,并且目標值在左半部分范圍內(nums[0] <= target && target < nums[mid]),移動右指針到 mid - 1;否則,移動左指針到 mid + 1。

如果右半部分有序,并且目標值在右半部分范圍內(nums[mid] < target && target <= nums[siz - 1]),移動左指針到 mid + 1;否則,移動右指針到 mid - 1。

第三步,如果循環結束仍未找到目標值,返回 -1。

假設數組為 [4, 5, 6, 7, 0, 1, 2],目標值 target 為 0,我們來模擬一下整個題解過程:

  • 1.初始 lef = 0,rig = 6,mid = 3,nums[mid] = 7。
  • 2.nums[0] <= nums[mid],左半部分有序。
  • 3. 0 不在左半部分范圍內,移動左指針 lef = 4。
  • 4.更新 mid = 5,nums[mid] = 1。
  • 5.nums[4] <= nums[mid],右半部分有序。
  • 6. 0 在右半部分范圍內,移動右指針 rig = 5。
  • 7.更新 mid = 4,nums[mid] = 0,找到目標值,返回 4。

總結

遇到 O(log n) 的題目,首先想到的就是二分查找,這道題也是一樣,只不過在二分查找的基礎上,增加了一些判斷條件。而二分查找的關鍵是找到有序的部分。

力扣鏈接:. - 力扣(LeetCode)

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

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

相關文章

古字畫3d立體在線數字展覽館更高效便捷

在數字時代的浪潮中&#xff0c;大連圖書館以嶄新的面貌躍然屏幕之上——3D全景圖書館。這座承載著城市文化精髓與豐富知識資源的數字圖書館&#xff0c;利用前沿的三維建模技術&#xff0c;為我們呈現了一個全新的知識世界。 隨時隨地&#xff0c;無論您身處何地&#xff0c;只…

獲得抖音商品評論 API 返回值

公共參數 名稱類型必須描述keyString是調用key&#xff08;獲取key和密鑰???????&#xff09;secretString是調用密鑰api_nameString是API接口名稱&#xff08;包括在請求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheString否[yes,no]默認yes&am…

信息學奧賽初賽天天練-22-C++基礎關鍵字、進制轉換、結構體與聯合體的實用技巧大揭秘

PDF文檔公眾號回復關鍵字:20240607 單項選擇題&#xff08;共15題&#xff0c;每題2分&#xff0c;共計30分&#xff1a;每題有且僅有一個正確選項&#xff09; 1 在C中&#xff0c;下面哪個關鍵字用于聲明一個變量&#xff0c;其值不能被修改&#xff1f;&#xff08; &#…

二叉樹講解升級版

目錄 二叉樹的存儲結構 二叉樹結點的查找和修改 二叉樹結點的插入 二叉樹的創建 二叉樹的遍歷 先序遍歷 中序遍歷 后序遍歷 層序遍歷 重建二叉樹 二叉樹的靜態實現 二叉樹的存儲結構 一般來說&#xff0c;二叉樹使用鏈表來定義。和普通鏈表的區別是&#xff0c;由于…

【Java】解決Java報錯:StackOverflowError

文章目錄 引言1. 錯誤詳解2. 常見的出錯場景2.1 無限遞歸2.2 遞歸深度過大2.3 方法調用層次過深 3. 解決方案3.1 優化遞歸算法3.2 尾遞歸優化3.3 增加調用棧大小3.4 檢查遞歸終止條件 4. 預防措施4.1 使用迭代替代遞歸4.2 尾遞歸優化4.3 合理設計遞歸算法4.4 調整JVM參數4.5 定…

b端系統類管理平臺設計前端開發案例

b端系統類管理平臺設計前端開發案例

二叉樹-堆的詳解

一&#xff0c;樹的概念 1&#xff0c;樹的概念 樹是一種非線性的數據結構&#xff0c;它是由n&#xff08;n>0&#xff09;個有限結點組成一個具有層次關系的集合。 把它叫做樹是因為它看起來像一棵倒掛的樹&#xff0c;也就是說它是根朝上&#xff0c;而葉朝下的。 有…

vue3 + echarts 二次開發百分比餅圖

效果圖&#xff1a; 安裝 pnpm i echarts 公共模塊組件 <divclass"pie"ref"percent"style"width: 100%; height: calc(100% - 48px)"></div> import { ref, onMounted } from vue import * as echarts from echarts const prop…

【JavaScript腳本宇宙】解密前端工具:選擇最佳JavaScript模塊管理工具

精選前端工具匯總&#xff1a;打包器和捆綁器的完整指南 前言 在現代Web開發中&#xff0c;使用適當的工具和庫可以極大地提高開發效率和項目質量。本文將介紹一些常用的Web應用程序捆綁器&#xff0c;這些工具能夠幫助開發人員有效地管理JavaScript模塊和資源。 歡迎訂閱專欄…

SpringBoot項目啟動提示端口號占用

Windows環境下&#xff0c;SpringBoot項目啟動時報端口號占用&#xff1a; *************************** APPLICATION FAILED TO START ***************************Description:Web server failed to start. Port 8080 was already in use.Action:Identify and stop the proc…

【樂吾樂3D可視化組態編輯器】狀態告警示例

狀態告警的設置方法為兩種&#xff1a; 1.通過數據點號設置&#xff08;推薦&#xff09;&#xff1a; 適用于綁定單一數據點號&#xff0c;設置邏輯簡潔&#xff0c;實現簡單邏輯交互 2.通過交互事件監聽數據點號設置&#xff1a; 適用于綁定多個數據點號&#xff0c;實現復…

LLM大模型AI應用的三階技術

第一階 指令工程&#xff08;Prompt Enginner&#xff09; 設計提示&#xff08;Prompt Design&#xff09; 結果優化&#xff08;Response Optimization&#xff09; 交互設計&#xff08;Interaction Design&#xff09; 模型理解&#xff08;Model Understanding&#…

哈希經典題目(C++)

文章目錄 前言一、兩數之和1.題目解析2.算法原理3.代碼編寫 二、判定是否互為字符重排1.題目解析2.算法原理3.代碼編寫 三、 字?異位詞分組1.題目解析2.算法原理3.代碼編寫 總結 前言 哈希表是一個存儲數據的容器&#xff0c;我們如果想要快速查找某個元素&#xff0c;就可以…

Python驅動下的AI革命:技術賦能與案例解析

在當今這個信息化、數據化的時代&#xff0c;人工智能&#xff08;AI&#xff09;已經成為推動社會發展的重要力量。而Python&#xff0c;作為一種簡單易學、功能強大的編程語言&#xff0c;在AI領域的應用中發揮著至關重要的作用。本文將探討Python在AI領域的應用、其背后的技…

MMUNet:形態學特征增強網絡在結腸癌病理圖像分割中的應用

MMUNet: Morphological feature enhancement network for colon cancer segmentation in pathological images. 發表在&#xff1a;Biomedical Signal Processing and Control2024--影響因子&#xff1a;3.137 南華大學的論文 論文地址&#xff1a;main.pdf (sciencedirecta…

Wakeup Source框架設計與實現

Wakeup Source 為系統組件提供了投票機制&#xff0c;以便低功耗子系統判斷當前是否可以進入休眠。 Wakeup Source(后簡稱&#xff1a;WS) 模塊可與內核中的其他模塊或者上層服務交互&#xff0c;并最終體現在對睡眠鎖的控制上。 1. 模塊功能說明 WS的處理邏輯基本上是圍繞 com…

后端進階-分庫分表

文章目錄 為什么需要分庫為什么需要分表 什么時候需要分庫分表只需要分庫只需要分表 分庫分表解決方案垂直分庫水平分庫垂直分表水平分表 分庫分表常用算法范圍算法hash分片查表分片 分庫分表模式客戶端模式代理模式 今天跟著訓練營學習了分庫分表&#xff0c;整理了學習筆記。…

機器學習模型進行預測和回測

這段代碼是為了并行地處理多個 CSV 文件&#xff0c;并使用機器學習模型進行預測和回測。主要涉及以下步驟&#xff1a; 初始化環境與設置&#xff1a; 引入必要的庫&#xff0c;如 ray 用于并行計算&#xff0c;pandas 用于數據處理&#xff0c;tqdm 用于進度條顯示等。設置一…

golang 不用sleep如何實現實現每隔指定時間執行一次for循環?

今天介紹的是在go語言里面不用time.Sleep&#xff0c; 使用for range 定時器管道 來實現按照我們指定的時間間隔來執行for循環, 即&#xff1a; for range ticker.C { } 這樣就實現了for每隔指定時間執行一次&#xff0c;除非管道被關閉&#xff0c;否則for而且會一直柱塞當前線…

淺說線性DP(下)

聲明 最近博主身體不適&#xff0c;更新較慢&#xff0c;請大家體諒體諒 最大上升子序列 【題目描述】 一個數的序列 你的任務&#xff0c;就是對于給定的序列&#xff0c;求出最大上升子序列和。注意&#xff0c;最長的上升子序列的和不一定是最大的&#xff0c;比如序列(1…