力扣分模組練習 二分查詢

2021-10-11 15:32:37 字數 4857 閱讀 7713

二分查詢思路簡單,但細節很搞人。個人習慣用左閉右開的區間寫法,以下是模板:

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...