劍指 Offer 11. 旋轉陣列的最小數字
劍指 Offer 11. 旋轉陣列的最小數字
劍指 Offer 11. 旋轉陣列的最小數字
把一個陣列最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。例如,陣列 [3,4,5,1,2] 為 [1,2,3,4,5] 的一個旋轉,該陣列的最小值為1。
示例 1:
輸入:[3,4,5,1,2]
輸出:1
示例 2:
輸入:[2,2,2,0,1]
輸出:0
思路1:遍歷
題目的意思:輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。
話說,管他是不是旋轉陣列,直接找出並返回陣列的最小值即可。
也就是:找出陣列的最小值
從前往後比較,遇到更小的替換,最後找出最小值
不難寫出程式碼:
class Solution {
public int minArray(int[] numbers) {
//邊界條件
if(numbers == null || numbers.length == 0) return 0;
int min = numbers[0];
for(int i = 0; i<numbers.length; i++){
if(numbers[i] < min)
{
min = numbers[i];
}
}
return min;
}
}
時間複雜度:O(n)
空間複雜度:O(1)
思路2:遍歷的優化
但是,這道題應該不是讓我們這樣解的,因為沒有使用到原陣列是排序好的陣列這個資訊。
假如,我們將輸入的旋轉後的陣列再次改變為排序好的陣列,那麼,直接找出陣列第一個元素就是最小值。
如何將輸入後的旋轉後的陣列再次改變為排序好的陣列呢?
可以從前往後找,找到一個前面的數字大於後一個數字的地方
可以從後往前找,找到一個前面的數字大於後一個數字的地方
其實,仔細想想,又沒有讓我們恢復排序陣列,那麼就沒有必要對陣列進行操作
那麼,我們只需要找到一個前面的數字大於後一個數字的地方即可
從前往後找:
class Solution {
public int minArray(int[] numbers) {
//邊界條件
if(numbers == null || numbers.length == 0) return 0;
//從前往後,找出第一個前面的數,大於後面的數的後面的數
int min = numbers[0];
for(int i = 0; i<numbers.length; i++){
if(numbers[i] < min)
{
min = numbers[i];
break;
}
}
return min;
}
}
比之前的程式,只是多了一個break
看了答案,解題是使用的二分查詢
這倒也對,排序的陣列,使用二分查詢效率要高
但,問題是,這個陣列也並不是排序的陣列,而是排序陣列的旋轉
這樣看來,這道題是考察二分查詢的變種,如何在旋轉後的排序陣列中,使用二分查詢找到最小值
思路3:二分查詢
假設:
最小值所在的位置為i,值nums[i] = x;
那麼,位置i之前的資料都小於x;位置i之後的資料都大於或等於x
為何前面是小於,後面是大於或等於呢?
比如[1,1,2,2,0,0]
那麼,最小值的位置index可以是4,也可以是5,因為兩個位置的值都是0
但,根據是排序的規則,我們可以預設第一個最小值為最小值,也就是index = 4的地方為最小值。
但是,最後求的是最小值,而不是位置,所以,index = 4或 index = 5都可以,反正最後返回的值都是0
其實,這裡,你也可以規定i之前的資料都是小於或等於x,i之後的資料都是大於x。
根據上面的特徵,可以得到nums[middle]的值,然後分情況討論:
- 如果nums[middle] > nums[height],說明最小值在middle的右邊
- 如果nums[middle] < nums[height],說明最小值在middle的左邊
- 如果nums[middle] == nums[height]
那麼,最小值不能確定在左邊還是右邊,
不能減少為minArray(numbers, low, middle);,有可能把最小值在右邊的情況忽略掉
但是,可以使得height - 1,這是因為,height - 1最多是middle的地方,也沒有把最小值忽略掉
根據以上思路,嘗試寫程式碼:
class Solution {
public int minArray(int[] numbers) {
//邊界條件
if(numbers == null || numbers.length == 0) return 0;
return minArray(numbers, 0, numbers.length - 1);
}
//左閉右開
public int minArray(int[] numbers, int low, int height)
{
// int middle = (height - low)/2;
int middle = low + (height - low)/2;
// = low + height/2 - low/2
// = height/2 + low/2;
if(low < height){
if(numbers[middle] > numbers[height]){
return minArray(numbers, middle + 1, height);
}else if(numbers[middle] < numbers[height]){
return minArray(numbers, low, middle);
}else{
return minArray(numbers, low, --height);
}
}else{
return numbers[low];
}
}
}
需要注意的地方:
int middle = (height - low)/2;❌
int middle = low + (height - low)/2;✅
int middle = (height + low)/2;✅
–height,因為要用到height - 1的結果
為何:minArray(numbers, middle + 1, height);
為何:minArray(numbers, low, middle);
你們不覺得這很怪異嗎?
為何前面的middle可以+1操作,而後面那個middle不可以做-1操作?
為何minArray(numbers, middle + 1, height);
能不能+1,是看+1後,會不會把最小值省略掉
如第一張圖,nums[middle + 1] > nums[middle],所以不會省略最小值
即使,nums[middle + 1]正好就是最小值,nums[middle + 1] < nums[middle]
而求的是minArray(numbers, middle + 1, height);,依然不會省略掉最小值,所以,此處middle + 1是可以的
為何minArray(numbers, low, middle);
能不能middle - 1,是看-1後,會不會把最小值省略掉
如第二張圖所示,nums[middle - 1] < nums[middle],不會省略最小值
問題是,如果nums[middle]此時正好就是最小值,那麼,nums[middle - 1] > nums[middle],此時minArray(numbers, low, middle - 1);就會把最小值nums[middle]給漏掉,因此,middle-1是不可以的
相關文章
- 【劍指 Offer】11. 旋轉陣列的最小數字陣列
- 劍指offer:旋轉陣列的最小數字陣列
- 劍指offer 旋轉陣列的最小數字陣列
- 【劍指offer】7.旋轉陣列的最小數字陣列
- 0二分查詢簡單 牛客NC.71旋轉陣列的最小數字 leetcode劍指 Offer 11. 旋轉陣列的最小數字陣列LeetCode
- (python版)《劍指Offer》JZ06:旋轉陣列的最小數字Python陣列
- 劍指offer-轉陣列的最小數字-php陣列PHP
- 劍指offer面試題11:旋轉陣列的最小數字(Java版已在牛客網AC)面試題陣列Java
- 劍指offer——把陣列排成最小的數C++陣列C++
- 劍指Offer-34-把陣列排成最小的數陣列
- 力扣 - 劍指 Offer 45. 把陣列排成最小的數力扣陣列
- 劍指Offer--陣列中重複的數字陣列
- 劍指Offer-把陣列中的數排成一個最小的數陣列
- 我請大家來刷題:旋轉陣列的最小數字陣列
- Leetcode 劍指 Offer 03. 陣列中重複的數字LeetCode陣列
- 《劍指Offer》- 連續子陣列的最大和或最小和陣列
- 劍指 Offer 56 - I. 陣列中數字出現的次數陣列
- 劍指OFFER-數字在升序陣列中出現的次數(Java)陣列Java
- 劍指Offer-39-數字在排序陣列中出現的次數排序陣列
- 面試:Java 實現查詢旋轉陣列的最小數字面試Java陣列
- 劍指offer之列印超過陣列一半的數字陣列
- 旋轉陣列中的最小元素陣列
- 劍指 offer(1) -- 陣列篇陣列
- 劍指offer刷題之路--1.陣列中重複的數字陣列
- 劍指Offer-31-最小的K個數
- [劍之offer] 03 陣列中重複的數字陣列
- 劍指offer之順序列印陣列陣列
- Leetcode 劍指 Offer 40. 最小的k個數LeetCode
- [劍指offer題解][Java]陣列中出現次數超過一半的數字Java陣列
- Leetcode 劍指 Offer 39. 陣列中出現次數超過一半的數字LeetCode陣列
- 【劍指offer】二維陣列中的查詢陣列
- 力扣 - 劍指 Offer 39. 陣列中出現次數超過一半的數字力扣陣列
- 劍指Offer-37-陣列中逆序對陣列
- 劍指offer——陣列中的逆序對C++(75%)陣列C++
- 【劍指offer】【1】二維陣列中的查詢陣列
- 每日一題 - 劍指 Offer 53 - I. 在排序陣列中查詢數字 I每日一題排序陣列
- 劍指offer——斐波那契數列
- nowcoder-劍指offer-二維陣列的查詢陣列