二分查詢思路簡單,但細節很搞人。個人習慣用左閉右開的區間寫法,以下是模板:
class
solution
else
if(nums[middle]
< target)
else
}return right;
// l r重疊,這裡寫left也可以}}
;
大意:實現 int sqrt(int x) 函式。
計算並返回 x 的平方根,其中 x 是非負整數。
由於返回型別是整數,結果只保留整數的部分,小數部分將被捨去。
樣例:輸入: 8
輸出: 2
說明: 8 的平方根是 2.82842…,
由於返回型別是整數,小數部分將被捨去。
思路:相當於求x方 - a = 0的解。所以就是在[0,a]之間二分法找乙個數可以x * x = a;
class
solution
return right-1;
//退出時,左右重合}}
;
大意:給定乙個按照公升序排列的整數陣列 nums,和乙個目標值 target。找出給定目標值在陣列中的開始位置和結束位置。
如果陣列中不存在目標值 target,返回 [-1, -1]。
樣例:輸入:nums = [5,7,7,8,8,10], target = 8
輸出:[3,4]
class
solution
;int lower =
lower_bound
(nums, target)
;int high =
high_bound
(nums, target);if
(lower == nums.
size()
|| nums[lower]
!= target)
//沒有賦值的情況
return vector<
int>
;return vector<
int>;}
intlower_bound
(vector<
int>
& nums,
int target)
return r;
//左閉右開寫法,最後 跳出來l == r所以這裡寫l,r都可以
}int
high_bound
(vector<
int>
& nums,
int target)
//尋找第乙個大於target的數
return r;}}
;
後面的區間問題,常用找下界函式來做,以下是本題引申出的模板:
不知道要不要寫等號的時候,想極端情況如,你找下界(第乙個大於等於的數)肯定等於的情況往左找啊。
int
low_bound
(vector<
int>
& vec,
int target)
//注意這裡是尋找第乙個大於或等於target的數字,即上題中的lowbound函式
return
(vec[r]
>= target)
? r:-1
;//如果小於說明target太大,沒找到
}
題意:給你乙個整數陣列 nums ,和乙個整數 target 。
該整數陣列原本是按公升序排列,但輸入時在預先未知的某個點上進行了旋轉。(例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。
請你在陣列中搜尋 target ,如果陣列中存在這個目標值,則返回它的索引,否則返回 -1 。
和下面那題的差別就是這題不允許重複。
class
solution
else
//左區間有序
}return-1
;}};
大意:假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。
( 例如,陣列 [0,0,1,2,2,5,6] 可能變為 [2,5,6,0,0,1,2] )。
編寫乙個函式來判斷給定的目標值是否存在於陣列中。若存在返回 true,否則返回 false。
即給的陣列是由某個遞增陣列平移變形而來的。
輸入: nums = [2,5,6,0,0,1,2], target = 0
輸出: true
思路:二分時,先找確定的區間。如確定右邊是有序的,而且target又可以落入區間內,就先去右邊找target。在這裡要注意,target必須在有序的範圍內(這裡上屆下屆都要寫,因為如果不寫,可能會漏查)。如果不在,就要到另一半區間去嘗試二分尋找。
如給陣列[3,1],和target = 3;
一開始判斷1是有序的遞增數列,如果不寫上界,就會直接結束程式,然而3是在mid的左邊。
class
solution
else
}return
false;}
};
唯一注意一點,注意r的初始寫法。這樣寫方便比較,可以把mid正好是最小值的情況納入下一步的尋找區間內。
class
solution
else
}return nums[l];}
};
題目:假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。
( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。
請找出其中最小的元素。
注意陣列中可能存在重複的元素。
樣例:輸入: [3,1,5]
輸出: 1
輸入: [2,2,2,2]
輸出: 2
本題核心思想:最小值一定不在判斷為有序的那一部分內。(因為陣列是旋轉平移得來的,所以最大和最小的交接是無序的,所以最小的那個數就在這個無序區間內)。
一開始沒想明白,自己寫的版本:
可以發現主要的坑點就是一直重複的那個數就是最小值,在沒法判斷有序區間的時候,不知道如何處理了。
class
solution
else
if(nums[mid]
> nums[left]
)//左邊有序
else
//右邊有序
}return min;}}
;
理清思路後,發現了本題核心思想。這樣在沒法判斷有序區間的時候把right減一,縮小這個區間。
這裡出現了第二個坑點,最好是用right-1(左閉右開寫法)指向的數來判斷有序區間,因為如果用left來做,在無法判斷的情況下要寫left++,這樣很容易陣列越界。
為什麼總喜歡和右邊比?
因為(l+r)/2是向下取整,也就是說,假如 l=0, r=1, 那麼mid = 0, 這樣就不能使用mid-1進行比較。反正之後都和右邊比就完事了。
(在下一題中十分明顯,所以養成習慣都和右邊比不容易出錯,右邊初始為 vec.size() -1)
此外左閉右開也可以寫成 right = nums.size() -1的。這樣可以方便當前區間最右邊的那個數的判斷。
class
solution
return nums[left];}
};
大意:給定乙個只包含整數的有序陣列,每個元素都會出現兩次,唯有乙個數隻會出現一次,找出這個數。
樣例:輸入: [1,1,2,3,3,4,4,8,8]
輸出: 2
本題核心思想:
如何判斷要去左邊還是右邊呢?就是通過左邊區間size的奇偶來判斷。這樣相當於在陣列之中一次刪除兩個相同的元素,並且分區間判斷。
同時,左閉右開只是left < right描述區間為1的時候是固定的,否則在討論low和high的移動的時候,總是死卡著這點容易陣列越界。
class
solution
else
if(nums[mid -1]
== nums[mid]
)//mid前面的數和mid相同
else
return nums[mid];}
return nums[low];}
};
峰值元素是指其值大於左右相鄰值的元素。
給定乙個輸入陣列 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素並返回其索引。
陣列可能包含多個峰值,在這種情況下,返回任何乙個峰值所在位置即可。
你可以假設 nums[-1] = nums[n] = -∞。
樣例:輸入: nums = [1,2,3,1]
輸出: 2
解釋: 3 是峰值元素,你的函式應該返回其索引 2。
思路:用當前mid的元素和mid+1的元素相比,如果小於則mid當前屬於乙個遞減區間。這樣peak必然在mid的左邊區間(這個新的查詢區間包含了mid本身)。去左邊區間進行新一輪二分查詢。
此外,因為(l+r)/2是向下取整,也就是說,假如 l=0, r=1, 那麼mid = 0, 這樣就不能使用mid-1進行比較。反正之後都和右邊比就完事了。
class
solution
return l;}}
;
力扣分模組練習 DFS與BFS
題意 給定乙個包含了一些 0 和 1 的非空二維陣列 grid 乙個 島嶼 是由一些相鄰的 1 代表土地 構成的組合,這裡的 相鄰 要求兩個 1 必須在水平或者豎直方向上相鄰。你可以假設 grid 的四個邊緣都被 0 代表水 包圍著。找到給定的二維陣列中最大的島嶼面積。如果沒有島嶼,則返回面積為 0...
力扣分模組練習 動態規劃 打家劫舍專題
參考題解 隨想錄 打家劫舍 ii 你是乙個專業的小偷,計畫偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都 圍成一圈 這意味著第乙個房屋和最後乙個房屋是緊挨著的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警 給定乙個代表每個房屋存放金額...
力扣分模組練習 雙指標 接雨水
11.盛最多水的容器 給你 n 個非負整數 a1,a2,an,每個數代表座標中的乙個點 i,ai 在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 i,ai 和 i,0 找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。說明 你不能傾斜容器。示例 輸入 1,8,6,2,5,4...