日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

旋转排序数组系列题详解

發(fā)布時(shí)間:2024/4/11 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 旋转排序数组系列题详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

旋轉(zhuǎn)排序數(shù)組系列題詳解

文章目錄

  • 旋轉(zhuǎn)排序數(shù)組系列題詳解
    • 一、問(wèn)題描述:旋轉(zhuǎn)數(shù)組的最小數(shù)字
    • 二、分析:二分查找
    • 三、代碼
    • 四、問(wèn)題描述:尋找旋轉(zhuǎn)排序數(shù)組中的最小值
    • 五、分析:二分搜索
    • 六、代碼
    • 七、問(wèn)題描述:尋找旋轉(zhuǎn)排序數(shù)組中的最小值 II
    • 八、分析:二分查找
    • 九、代碼
    • 十、問(wèn)題描述:搜索旋轉(zhuǎn)排序數(shù)組
    • 十一、分析:二分搜索
    • 十二、代碼
    • 十三、問(wèn)題描述:搜索旋轉(zhuǎn)排序數(shù)組II
    • 十四、代碼

一、問(wèn)題描述:旋轉(zhuǎn)數(shù)組的最小數(shù)字

二、分析:二分查找

一個(gè)包含重復(fù)元素的升序數(shù)組在經(jīng)過(guò)旋轉(zhuǎn)之后,可以得到下面可視化的折線圖:

  • 其中橫軸表示數(shù)組元素的下標(biāo),縱軸表示數(shù)組元素的值。圖中標(biāo)出了最小值的位置,是我們需要旋轉(zhuǎn)的目標(biāo)。

  • 我們考慮數(shù)組中的最后一個(gè)元素 x:在最小值右側(cè)的元素,它們的值一定都小于等于 x;而在最小值左側(cè)的元素,它們的值一定都大于等于 x。因此,我們可以根據(jù)這一條性質(zhì),通過(guò)二分查找的方法找出最小值。

  • 在二分查找的每一步中,左邊界為 low,右邊界為high,區(qū)間的中點(diǎn)為 pivot,最小值就在該區(qū)間內(nèi)。我們將中軸元素numbers[pivot] 與右邊界元素 numbers[high] 進(jìn)行比較,可能會(huì)有以下的三種情況:

  • 第一種情況是numbers[pivot]<numbers[high]

如下圖所示,這說(shuō)明numbers[pivot] 是最小值右側(cè)的元素,因此我們可以忽略二分查找區(qū)間的右半部分。

  • 第二種情況是numbers[pivot]>numbers[high]

如下圖所示,這說(shuō)明 numbers[pivot] 是最小值左側(cè)的元素,因此我們可以忽略二分查找區(qū)間的左半部分。

  • 第三種情況是numbers[pivot]==numbers[high]。

如下圖所示,由于重復(fù)元素的存在,我們并不能確定 numbers[pivot] 究竟在最小值的左側(cè)還是右側(cè),因此我們不能莽撞地忽略某一部分的元素。

我們唯一可以知道的是,由于它們的值相同,所以無(wú)論numbers[high] 是不是最小值,都有一個(gè)它的「替代品numbers[pivot],因此我們可以忽略二分查找區(qū)間的右端點(diǎn)。

  • 當(dāng)二分查找結(jié)束時(shí),我們就得到了最小值所在的位置。

三、代碼

class Solution { public:int minArray(vector<int>& numbers) {int low = 0;int high = numbers.size() - 1;while (low < high) {int pivot = low + (high - low) / 2;if (numbers[pivot] < numbers[high]) {high = pivot;}else if (numbers[pivot] > numbers[high]) {low = pivot + 1;}else {high -= 1;}}return numbers[low];} };

四、問(wèn)題描述:尋找旋轉(zhuǎn)排序數(shù)組中的最小值

五、分析:二分搜索

一種暴力的解法是搜索整個(gè)數(shù)組,找到其中的最小元素,這樣的時(shí)間復(fù)雜度是 O(N)其中 N 是給定數(shù)組的大小。

  • 一個(gè)非常棒的解決該問(wèn)題的辦法是使用二分搜索。在二分搜索中,我們找到區(qū)間的中間點(diǎn)并根據(jù)某些條件決定去區(qū)間左半部分還是右半部分搜索。

  • 由于給定的數(shù)組是有序的,我們就可以使用二分搜索。然而,數(shù)組被旋轉(zhuǎn)了,所以簡(jiǎn)單的使用二分搜索并不可行。

  • 在這個(gè)問(wèn)題中,我們使用一種改進(jìn)的二分搜索,判斷條件與標(biāo)準(zhǔn)的二分搜索有些不同。

  • 我們希望找到旋轉(zhuǎn)排序數(shù)組的最小值,如果數(shù)組沒(méi)有被旋轉(zhuǎn)呢?如何檢驗(yàn)這一點(diǎn)呢?

  • 如果數(shù)組沒(méi)有被旋轉(zhuǎn),是升序排列,就滿足 last element > first element。

  • 上圖例子中 7>2 。說(shuō)明數(shù)組仍然是有序的,沒(méi)有被旋轉(zhuǎn)。

  • 上面的例子中 3 < 4,因此數(shù)組旋轉(zhuǎn)過(guò)了。這是因?yàn)樵鹊臄?shù)組為 [2, 3, 4, 5, 6, 7],通過(guò)旋轉(zhuǎn)較小的元素 [2, 3] 移到了后面,也就是 [4, 5, 6, 7, 2, 3]。因此旋轉(zhuǎn)數(shù)組中第一個(gè)元素 [4] 變得比最后一個(gè)元素大。

  • 這意味著在數(shù)組中你會(huì)發(fā)現(xiàn)一個(gè)變化的點(diǎn),這個(gè)點(diǎn)會(huì)幫助我們解決這個(gè)問(wèn)題,我們稱其為變化點(diǎn)。

  • 在這個(gè)改進(jìn)版本的二分搜索算法中,我們需要找到這個(gè)點(diǎn)。下面是關(guān)于變化點(diǎn)的特點(diǎn):

  • 所有變化點(diǎn)左側(cè)元素 > 數(shù)組第一個(gè)元素

  • 所有變化點(diǎn)右側(cè)元素 < 數(shù)組第一個(gè)元素

  • 算法

  • 找到數(shù)組的中間元素 mid。

  • 如果中間元素 > 數(shù)組第一個(gè)元素,我們需要在 mid 右邊搜索變化點(diǎn)。

  • 如果中間元素 < 數(shù)組第一個(gè)元素,我們需要在 mid 做邊搜索變化點(diǎn)。

  • 上面的例子中,中間元素 6 比第一個(gè)元素 4 大,因此在中間點(diǎn)右側(cè)繼續(xù)搜索。

  • 當(dāng)我們找到變化點(diǎn)時(shí)停止搜索,當(dāng)以下條件滿足任意一個(gè)即可:

  • nums[mid] > nums[mid + 1],因此 mid+1 是最小值。

  • nums[mid - 1] > nums[mid],因此 mid 是最小值。

  • 在上面的例子中,標(biāo)記左右區(qū)間端點(diǎn)。中間元素為 2,之后的元素是 7 滿足 7 > 2 也就是 nums[mid - 1] > nums[mid]。因此找到變化點(diǎn)也就是最小元素為 2。

六、代碼

class Solution { public:int findMin(vector<int>& nums) {if (nums.size() == 1) {return nums[0];}int left = 0, right = nums.size() - 1;if (nums[right] > nums[0]) {return nums[0];}while (right >= left) {int mid = left + (right - left) / 2;if (nums[mid] > nums[mid + 1]) {return nums[mid + 1];}if (nums[mid - 1] > nums[mid]) {return nums[mid];}if (nums[mid] > nums[0]) {left = mid + 1;} else {right = mid - 1;}}return -1;} };

七、問(wèn)題描述:尋找旋轉(zhuǎn)排序數(shù)組中的最小值 II

八、分析:二分查找

  • 一個(gè)包含重復(fù)元素的升序數(shù)組在經(jīng)過(guò)旋轉(zhuǎn)之后,可以得到下面可視化的折線圖:

  • 其中橫軸表示數(shù)組元素的下標(biāo),縱軸表示數(shù)組元素的值。圖中標(biāo)出了最小值的位置,是我們需要旋轉(zhuǎn)的目標(biāo)。

  • 我們考慮數(shù)組中的最后一個(gè)元素 x:在最小值右側(cè)的元素,它們的值一定都小于等于 x;而在最小值左側(cè)的元素,它們的值一定都大于等于 x。因此,我們可以根據(jù)這一條性質(zhì),通過(guò)二分查找的方法找出最小值。

  • 在二分查找的每一步中,左邊界為low,右邊界為high,區(qū)間的中點(diǎn)為pivot,最小值就在該區(qū)間內(nèi)。

  • 我們將中軸元素nums[pivot] 與右邊界元素nums[high] 進(jìn)行比較,可能會(huì)有以下的三種情況:

  • 第一種情況是nums[pivot]<nums[high]。

如下圖所示,這說(shuō)明nums[pivot] 是最小值右側(cè)的元素,因此我們可以忽略二分查找區(qū)間的右半部分。

  • 第二種情況是nums[pivot]>nums[high]。

如下圖所示,這說(shuō)明 nums[pivot] 是最小值左側(cè)的元素,因此我們可以忽略二分查找區(qū)間的左半部分。

  • 第三種情況是 nums[pivot]==nums[high]。

如下圖所示,由于重復(fù)元素的存在,我們并不能確定nums[pivot] 究竟在最小值的左側(cè)還是右側(cè),因此我們不能莽撞地忽略某一部分的元素。

我們唯一可以知道的是,由于它們的值相同,所以無(wú)論 nums[high] 是不是最小值,都有一個(gè)它的「替代品」nums[pivot],因此我們可以忽略二分查找區(qū)間的右端點(diǎn)。

  • 當(dāng)二分查找結(jié)束時(shí),我們就得到了最小值所在的位置。

九、代碼

class Solution { public:int findMin(vector<int>& nums) {int low = 0;int high = nums.size() - 1;while (low < high) {int pivot = low + (high - low) / 2;if (nums[pivot] < nums[high]) {high = pivot;}else if (nums[pivot] > nums[high]) {low = pivot + 1;}else {high -= 1;}}return nums[low];} };

十、問(wèn)題描述:搜索旋轉(zhuǎn)排序數(shù)組

十一、分析:二分搜索

題目要求算法時(shí)間復(fù)雜度必須是 O(logn)O(logn)O(logn) 的級(jí)別,這提示我們可以使用二分搜索的方法。

  • 但是數(shù)組本身不是有序的,進(jìn)行旋轉(zhuǎn)后只保證了數(shù)組的局部是有序的,這還能進(jìn)行二分搜索嗎?答案是可以的。
  • 可以發(fā)現(xiàn)的是,我們將數(shù)組從中間分開成左右兩部分的時(shí)候,一定有一部分的數(shù)組是有序的。
  • 拿示例來(lái)看,我們從 6 這個(gè)位置分開以后數(shù)組變成了 [4, 5, 6] 和 [7, 0, 1, 2] 兩個(gè)部分,其中左邊 [4, 5, 6]這個(gè)部分的數(shù)組是有序的,其他也是如此。
  • 這啟示我們可以在常規(guī)二分搜索的時(shí)候查看當(dāng)前 mid 為分割位置分割出來(lái)的兩個(gè)部分 [l, mid] 和 [mid + 1, r]
  • 看哪個(gè)部分是有序的,并根據(jù)有序的那個(gè)部分確定我們?cè)撊绾胃淖兌炙阉鞯纳舷陆?#xff0c;因?yàn)槲覀兡軌蚋鶕?jù)有序的那部分判斷出 target 在不在這個(gè)部分:
  • 如果 [l, mid - 1] 是有序數(shù)組,且 target 的大小滿足 [nums[l],nums[mid]),則我們應(yīng)該將搜索范圍縮小至 [l, mid - 1],否則在 [mid + 1, r] 中尋找。
  • 如果 [mid, r] 是有序數(shù)組,且 target 的大小滿足(nums[mid+1],nums[r]],則我們應(yīng)該將搜索范圍縮小至 [mid + 1, r],否則在 [l, mid - 1] 中尋找。

  • 需要注意的是,二分的寫法有很多種,所以在判斷 target 大小與有序部分的關(guān)系的時(shí)候可能會(huì)出現(xiàn)細(xì)節(jié)上的差別。

十二、代碼

class Solution { public:int search(vector<int>& nums, int target) {int n = (int)nums.size();if (!n) return -1;if (n == 1) return nums[0] == target ? 0 : -1;//左右邊界int l = 0, r = n - 1;while (l <= r) {//中間的值int mid = (l + r) >> 1;//相等直接返回if (nums[mid] == target) return mid;//代表【l,mid】是有序的if (nums[0] <= nums[mid]) {//如果目標(biāo)值target滿足【nums[0],nums[mid])代表在//左半?yún)^(qū)間查找if (nums[0] <= target && target < nums[mid]) {r = mid - 1;} //反之右半?yún)^(qū)間查找else {l = mid + 1;}} //代表(mid,r】是有序的else {//在右半?yún)^(qū)間查找if (nums[mid] < target && target <= nums[n - 1]) {l = mid + 1;} //在左半?yún)^(qū)間查找else {r = mid - 1;}}}return -1;} };

十三、問(wèn)題描述:搜索旋轉(zhuǎn)排序數(shù)組II

十四、代碼

class Solution { public:bool search(vector<int>& nums, int target) {int left = 0,right = nums.size() - 1;while(left <= right){while(left != right && nums[left] == nums[right]) right--; //無(wú)重復(fù)值的解法中添加這行int mid = (left + right) / 2;if(nums[mid] == target) return true;else if(nums[mid] > target){if(nums[mid] > nums[right] && target < nums[left]) left = mid + 1;else right = mid - 1;}else{if(nums[mid] < nums[left] && target > nums[right]) right=mid-1;else left = mid + 1;}}return false;} };

總結(jié)

以上是生活随笔為你收集整理的旋转排序数组系列题详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。