成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

在排序數組中查找元素的第一個和最后一個位置

開發 前端
給定一個按照升序排列的整數數組 nums,和一個目標值 target。找出給定目標值在數組中的開始位置和結束位置。

[[440116]]

這個就是考察二分法的進階題目了

在排序數組中查找元素的第一個和最后一個位置

給定一個按照升序排列的整數數組 nums,和一個目標值 target。找出給定目標值在數組中的開始位置和結束位置。

如果數組中不存在目標值 target,返回 [-1, -1]。

進階:你可以設計并實現時間復雜度為 O(log n) 的算法解決此問題嗎?

示例 1:

  • 輸入:nums = [5,7,7,8,8,10], target = 8
  • 輸出:[3,4]

示例 2:

  • 輸入:nums = [5,7,7,8,8,10], target = 6
  • 輸出:[-1,-1]

示例 3:

  • 輸入:nums = [], target = 0
  • 輸出:[-1,-1]

思路

這道題目如果基礎不是很好,不建議大家看簡短的代碼,簡短的代碼隱藏了太多邏輯,結果就是稀里糊涂把題AC了,但是沒有想清楚具體細節!

對二分還不了解的同學先做這兩題:

  • 704.二分查找
  • 35.搜索插入位置

下面我來把所有情況都討論一下。

尋找target在數組里的左右邊界,有如下三種情況:

  • 情況一:target 在數組范圍的右邊或者左邊,例如數組{3, 4, 5},target為2或者數組{3, 4, 5},target為6,此時應該返回{-1, -1}
  • 情況二:target 在數組范圍中,且數組中不存在target,例如數組{3,6,7},target為5,此時應該返回{-1, -1}
  • 情況三:target 在數組范圍中,且數組中存在target,例如數組{3,6,7},target為6,此時應該返回{1, 1}

這三種情況都考慮到,說明就想的很清楚了。

接下來,在去尋找左邊界,和右邊界了。

采用二分法來去尋找左右邊界,為了讓代碼清晰,我分別寫兩個二分來尋找左邊界和右邊界。

剛剛接觸二分搜索的同學不建議上來就像如果用一個二分來查找左右邊界,很容易把自己繞進去,建議扎扎實實的寫兩個二分分別找左邊界和右邊界

尋找右邊界

先來尋找右邊界,至于二分查找,如果看過704.二分查找就會知道,二分查找中什么時候用while (left <= right),有什么時候用while (left < right),其實只要清楚循環不變量,很容易區分兩種寫法。

那么這里我采用while (left <= right)的寫法,區間定義為[left, right],即左閉又閉的區間(如果這里有點看不懂了,強烈建議把704.二分查找這篇文章先看了,704題目做了之后再做這道題目就好很多了)

確定好:計算出來的右邊界是不包好target的右邊界,左邊界同理。

可以寫出如下代碼

  1. // 二分查找,尋找target的右邊界(不包括target) 
  2. // 如果rightBorder為沒有被賦值(即target在數組范圍的左邊,例如數組[3,3],target為2),為了處理情況一 
  3. int getRightBorder(vector<int>& nums, int target) { 
  4.     int left = 0; 
  5.     int right = nums.size() - 1; // 定義target在左閉右閉的區間里,[leftright
  6.     int rightBorder = -2; // 記錄一下rightBorder沒有被賦值的情況 
  7.     while (left <= right) { // 當left==right,區間[leftright]依然有效 
  8.         int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2 
  9.         if (nums[middle] > target) { 
  10.             right = middle - 1; // target 在左區間,所以[left, middle - 1] 
  11.         } else { // 當nums[middle] == target的時候,更新left,這樣才能得到target的右邊界 
  12.             left = middle + 1; 
  13.             rightBorder = left
  14.         } 
  15.     } 
  16.     return rightBorder; 

尋找左邊界

  1. // 二分查找,尋找target的左邊界leftBorder(不包括target) 
  2. // 如果leftBorder沒有被賦值(即target在數組范圍的右邊,例如數組[3,3],target為4),為了處理情況一 
  3. int getLeftBorder(vector<int>& nums, int target) { 
  4.     int left = 0; 
  5.     int right = nums.size() - 1; // 定義target在左閉右閉的區間里,[leftright
  6.     int leftBorder = -2; // 記錄一下leftBorder沒有被賦值的情況 
  7.     while (left <= right) { 
  8.         int middle = left + ((right - left) / 2); 
  9.         if (nums[middle] >= target) { // 尋找左邊界,就要在nums[middle] == target的時候更新right 
  10.             right = middle - 1; 
  11.             leftBorder = right
  12.         } else { 
  13.             left = middle + 1; 
  14.         } 
  15.     } 
  16.     return leftBorder; 

處理三種情況

左右邊界計算完之后,看一下主體代碼,這里把上面討論的三種情況,都覆蓋了

  1. class Solution { 
  2. public
  3.     vector<int> searchRange(vector<int>& nums, int target) { 
  4.         int leftBorder = getLeftBorder(nums, target); 
  5.         int rightBorder = getRightBorder(nums, target); 
  6.         // 情況一 
  7.         if (leftBorder == -2 || rightBorder == -2) return {-1, -1}; 
  8.         // 情況三 
  9.         if (rightBorder - leftBorder > 1) return {leftBorder + 1, rightBorder - 1}; 
  10.         // 情況二 
  11.         return {-1, -1}; 
  12.     } 
  13. private: 
  14.      int getRightBorder(vector<int>& nums, int target) { 
  15.         int left = 0; 
  16.         int right = nums.size() - 1; 
  17.         int rightBorder = -2; // 記錄一下rightBorder沒有被賦值的情況 
  18.         while (left <= right) { 
  19.             int middle = left + ((right - left) / 2); 
  20.             if (nums[middle] > target) { 
  21.                 right = middle - 1; 
  22.             } else { // 尋找右邊界,nums[middle] == target的時候更新left 
  23.                 left = middle + 1; 
  24.                 rightBorder = left
  25.             } 
  26.         } 
  27.         return rightBorder; 
  28.     } 
  29.     int getLeftBorder(vector<int>& nums, int target) { 
  30.         int left = 0; 
  31.         int right = nums.size() - 1; 
  32.         int leftBorder = -2; // 記錄一下leftBorder沒有被賦值的情況 
  33.         while (left <= right) { 
  34.             int middle = left + ((right - left) / 2); 
  35.             if (nums[middle] >= target) { // 尋找左邊界,nums[middle] == target的時候更新right 
  36.                 right = middle - 1; 
  37.                 leftBorder = right
  38.             } else { 
  39.                 left = middle + 1; 
  40.             } 
  41.         } 
  42.         return leftBorder; 
  43.     } 
  44. }; 

這份代碼在簡潔性很有大的優化空間,例如把尋找左右區間函數合并一起。

但拆開更清晰一些,而且把三種情況以及對應的處理邏輯完整的展現出來了。

總結

初學者建議大家一塊一塊的去分拆這道題目,正如本題解描述,想清楚三種情況之后,先專注于尋找右區間,然后專注于尋找左區間,左右根據左右區間做最后判斷。

不要上來就想如果一起尋找左右區間,搞著搞著就會顧此失彼,繞進去拔不出來了。

其他語言版本

Java

  1. class Solution { 
  2.     int[] searchRange(int[] nums, int target) { 
  3.         int leftBorder = getLeftBorder(nums, target); 
  4.         int rightBorder = getRightBorder(nums, target); 
  5.         // 情況一 
  6.         if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1}; 
  7.         // 情況三 
  8.         if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1}; 
  9.         // 情況二 
  10.         return new int[]{-1, -1}; 
  11.     } 
  12.  
  13.     int getRightBorder(int[] nums, int target) { 
  14.         int left = 0; 
  15.         int right = nums.length - 1; 
  16.         int rightBorder = -2; // 記錄一下rightBorder沒有被賦值的情況 
  17.         while (left <= right) { 
  18.             int middle = left + ((right - left) / 2); 
  19.             if (nums[middle] > target) { 
  20.                 right = middle - 1; 
  21.             } else { // 尋找右邊界,nums[middle] == target的時候更新left 
  22.                 left = middle + 1; 
  23.                 rightBorder = left
  24.             } 
  25.         } 
  26.         return rightBorder; 
  27.     } 
  28.  
  29.     int getLeftBorder(int[] nums, int target) { 
  30.         int left = 0; 
  31.         int right = nums.length - 1; 
  32.         int leftBorder = -2; // 記錄一下leftBorder沒有被賦值的情況 
  33.         while (left <= right) { 
  34.             int middle = left + ((right - left) / 2); 
  35.             if (nums[middle] >= target) { // 尋找左邊界,nums[middle] == target的時候更新right 
  36.                 right = middle - 1; 
  37.                 leftBorder = right
  38.             } else { 
  39.                 left = middle + 1; 
  40.             } 
  41.         } 
  42.         return leftBorder; 
  43.     } 
  1. // 解法2 
  2. // 1、首先,在 nums 數組中二分查找 target; 
  3. // 2、如果二分查找失敗,則 binarySearch 返回 -1,表明 nums 中沒有 target。此時,searchRange 直接返回 {-1, -1}; 
  4. // 3、如果二分查找成功,則 binarySearch 返回 nums 中值為 target 的一個下標。然后,通過左右滑動指針,來找到符合題意的區間 
  5.  
  6. class Solution { 
  7.  public int[] searchRange(int[] nums, int target) { 
  8.   int index = binarySearch(nums, target); // 二分查找 
  9.  
  10.   if (index == -1) { // nums 中不存在 target,直接返回 {-1, -1} 
  11.    return new int[] {-1, -1}; // 匿名數組 
  12.   } 
  13.   // nums 中存在 targe,則左右滑動指針,來找到符合題意的區間 
  14.   int left = index
  15.   int right = index
  16.         // 向左滑動,找左邊界 
  17.   while (left - 1 >= 0 && nums[left - 1] == nums[index]) { // 防止數組越界。邏輯短路,兩個條件順序不能換 
  18.    left--; 
  19.   } 
  20.         // 向左滑動,找右邊界 
  21.   while (right + 1 < nums.length && nums[right + 1] == nums[index]) { // 防止數組越界。 
  22.    right++; 
  23.   } 
  24.   return new int[] {leftright}; 
  25.     } 
  26.  
  27.  /** 
  28.   * 二分查找 
  29.   * @param nums 
  30.   * @param target 
  31.   */ 
  32.  public int binarySearch(int[] nums, int target) { 
  33.   int left = 0; 
  34.   int right = nums.length - 1; // 不變量:左閉右閉區間 
  35.  
  36.   while (left <= right) { // 不變量:左閉右閉區間 
  37.    int mid = left + (right - left) / 2; 
  38.    if (nums[mid] == target) { 
  39.     return mid; 
  40.    } else if (nums[mid] < target) { 
  41.     left = mid + 1; 
  42.    } else { 
  43.     right = mid - 1; // 不變量:左閉右閉區間 
  44.    } 
  45.   } 
  46.   return -1; // 不存在 
  47.  } 

Python

  1. class Solution: 
  2.     def searchRange(self, nums: List[int], target: int) -> List[int]: 
  3.         def getRightBorder(nums:List[int], target:int) -> int
  4.             leftright = 0, len(nums)-1 
  5.             rightBoder = -2 # 記錄一下rightBorder沒有被賦值的情況 
  6.             while left <= right
  7.                 middle = left + (right-left) // 2 
  8.                 if nums[middle] > target: 
  9.                     right = middle - 1 
  10.                 else: # 尋找右邊界,nums[middle] == target的時候更新left 
  11.                     left = middle + 1 
  12.                     rightBoder = left 
  13.  
  14.             return rightBoder 
  15.  
  16.         def getLeftBorder(nums:List[int], target:int) -> int
  17.             leftright = 0, len(nums)-1 
  18.             leftBoder = -2 # 記錄一下leftBorder沒有被賦值的情況 
  19.             while left <= right
  20.                 middle = left + (right-left) // 2 
  21.                 if nums[middle] >= target: #  尋找左邊界,nums[middle] == target的時候更新right 
  22.                     right = middle - 1; 
  23.                     leftBoder = right
  24.                 else
  25.                     left = middle + 1 
  26.             return leftBoder 
  27.         leftBoder = getLeftBorder(nums, target) 
  28.         rightBoder = getRightBorder(nums, target) 
  29.         # 情況一 
  30.         if leftBoder == -2 or rightBoder == -2: return [-1, -1] 
  31.         # 情況三 
  32.         if rightBoder -leftBoder >1: return [leftBoder + 1, rightBoder - 1] 
  33.         # 情況二 
  34.         return [-1, -1] 
  1. # 解法2 
  2. # 1、首先,在 nums 數組中二分查找 target; 
  3. # 2、如果二分查找失敗,則 binarySearch 返回 -1,表明 nums 中沒有 target。此時,searchRange 直接返回 {-1, -1}; 
  4. # 3、如果二分查找成功,則 binarySearch 返回 nums 中值為 target 的一個下標。然后,通過左右滑動指針,來找到符合題意的區間 
  5. class Solution: 
  6.     def searchRange(self, nums: List[int], target: int) -> List[int]: 
  7.         def binarySearch(nums:List[int], target:int) -> int
  8.             leftright = 0, len(nums)-1 
  9.             while left<=right: # 不變量:左閉右閉區間 
  10.                 middle = left + (right-left) // 2 
  11.                 if nums[middle] > target: 
  12.                     right = middle - 1 
  13.                 elif nums[middle] < target: 
  14.                     left = middle + 1 
  15.                 else
  16.                     return middle 
  17.             return -1 
  18.         index = binarySearch(nums, target) 
  19.         if index == -1:return [-1, -1] # nums 中不存在 target,直接返回 {-1, -1} 
  20.         # nums 中存在 targe,則左右滑動指針,來找到符合題意的區間 
  21.         leftright = indexindex 
  22.         # 向左滑動,找左邊界 
  23.         while left -1 >=0 and nums[left - 1] == target: left -=1 
  24.         # 向右滑動,找右邊界 
  25.         while right+1 < len(nums) and nums[right + 1] == target: right +=1 
  26.         return [leftright
  1. # 解法3 
  2. # 1、首先,在 nums 數組中二分查找得到第一個大于等于 target的下標(左邊界)與第一個大于target的下標(右邊界); 
  3. # 2、如果左邊界<= 右邊界,則返回 [左邊界, 右邊界]。否則返回[-1, -1] 
  4. class Solution: 
  5.     def searchRange(self, nums: List[int], target: int) -> List[int]: 
  6.         def binarySearch(nums:List[int], target:intlower:bool) -> int
  7.             leftright = 0, len(nums)-1 
  8.             ans = len(nums) 
  9.             while left<=right: # 不變量:左閉右閉區間 
  10.                 middle = left + (right-left) //2 
  11.                 # lowerTrue,執行前半部分,找到第一個大于等于 target的下標 ,否則找到第一個大于target的下標 
  12.                 if nums[middle] > target or (lower and nums[middle] >= target): 
  13.                     right = middle - 1 
  14.                     ans = middle 
  15.                 else
  16.                     left = middle + 1 
  17.             return ans 
  18.  
  19.         leftBorder = binarySearch(nums, target, True) # 搜索左邊界 
  20.         rightBorder = binarySearch(nums, target, False) -1  # 搜索右邊界 
  21.         if leftBorder<= rightBorder and rightBorder< len(nums) and nums[leftBorder] == target and  nums[rightBorder] == target: 
  22.             return [leftBorder, rightBorder] 
  23.         return [-1, -1] 
  1. # 解法4 
  2. # 1、首先,在 nums 數組中二分查找得到第一個大于等于 target的下標leftBorder; 
  3. # 2、在 nums 數組中二分查找得到第一個大于等于 target+1的下標, 減1則得到rightBorder; 
  4. # 3、如果開始位置在數組的右邊或者不存在target,則返回[-1, -1] 。否則返回[leftBorder, rightBorder] 
  5. class Solution: 
  6.     def searchRange(self, nums: List[int], target: int) -> List[int]: 
  7.         def binarySearch(nums:List[int], target:int) -> int
  8.             leftright = 0, len(nums)-1 
  9.             while left<=right: # 不變量:左閉右閉區間 
  10.                 middle = left + (right-left) //2 
  11.                 if nums[middle] >= target: 
  12.                     right = middle - 1 
  13.                 else
  14.                     left = middle + 1 
  15.             return left  # 若存在target,則返回第一個等于target的值 
  16.  
  17.         leftBorder = binarySearch(nums, target) # 搜索左邊界 
  18.         rightBorder = binarySearch(nums, target+1) -1  # 搜索右邊界 
  19.         if leftBorder == len(nums) or nums[leftBorder]!= target: # 情況一和情況二 
  20.             return [-1, -1] 
  21.         return [leftBorder, rightBorder] 

 

責任編輯:姜華 來源: 代碼隨想錄
相關推薦

2021-11-02 14:54:41

排序數組元素

2024-03-18 09:50:18

Selenium元素Python

2024-06-06 08:46:26

彈性布局元素瀏覽器

2020-11-13 07:08:51

Spring Boot應用Spring

2010-07-05 17:00:39

SQL server

2013-10-30 22:10:28

Clouda程序

2022-10-17 10:28:05

Web 組件代碼

2023-09-21 22:43:17

Django框架

2021-04-07 13:38:27

Django項目視圖

2010-07-30 14:58:06

Flex應用

2011-03-21 14:24:13

Debian 6

2013-01-14 09:44:58

JavaScriptJSJS框架

2011-03-03 21:04:08

bug程序員

2012-02-08 11:15:38

HibernateJava

2021-08-26 07:43:44

vectorerase錯誤

2014-07-21 10:25:12

ENode開發論壇

2011-06-24 13:38:32

QT 編譯 安裝

2019-12-31 08:00:00

DebianLinuxApple Swift

2021-11-02 08:00:00

機器學習API技術

2025-05-28 09:04:00

谷歌AI搜索
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美一区二区三区在线 | 毛片网站在线观看 | 亚洲精品一区二区另类图片 | 成人精品一区亚洲午夜久久久 | 国产免费观看视频 | 国产精品久久久久免费 | 奇米久久 | 国产精品日韩欧美一区二区 | 久久网国产 | 日韩综合网 | 伊人狼人影院 | 久久久久九九九女人毛片 | 亚洲在线| 欧美成人精品一区二区男人看 | 伊人亚洲 | 国产精品久久久久久久久 | 国产成人精品久久 | 久久精品国产一区 | 在线视频成人 | 欧美极品在线观看 | 99热精品国产 | 一级一级毛片免费看 | 欧美美乳| 久久久久久久久久久国产 | 91玖玖 | 久久精品二区亚洲w码 | 欧美一区二区三区免费电影 | 精品国产一区二区三区久久久蜜月 | 黄色大片在线播放 | 日本视频免费观看 | 成年人在线观看 | 亚洲精品在线91 | 午夜影晥 | 51ⅴ精品国产91久久久久久 | 日韩欧美国产精品 | 亚洲二区视频 | 男人的天堂avav| 欧美日韩一区二区三区在线观看 | 成人午夜免费福利视频 | 国产精品99久久久久久宅男 | 久久99深爱久久99精品 |