二分法查找平方和_面试手撕系列:二分法
生活随笔
收集整理的這篇文章主要介紹了
二分法查找平方和_面试手撕系列:二分法
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
最近春招開始了,面試面著面著一言不合就開始手撕代碼手撕就手撕,接下來我打算寫幾個專題講講面試中手撕的常見題目?這些都是LeetCode上有的題目?手撕無非就是?樹、鏈表、二分、字符串這些常用的數(shù)據(jù)結(jié)構(gòu)所以接下來請關(guān)注我們的專題吧二分法二分法查找,也稱為折半法,是一種在有序數(shù)組中查找特定元素的搜索算法。二分法查找的思路如下:(1)首先,從數(shù)組的中間元素開始搜索,如果該元素正好是目標(biāo)元素,則搜索過程結(jié)束,否則執(zhí)行下一步。(2)如果目標(biāo)元素大于/小于中間元素,則在數(shù)組大于/小于中間元素的那一半?yún)^(qū)域查找,然后重復(fù)步驟(1)的操作。(3)如果某一步數(shù)組為空,則表示找不到目標(biāo)元素。二分法查找的時間復(fù)雜度O(logn)。感覺很抽象的樣子 舉一個簡單通俗易懂的例子你不知道自己長得怎么樣,然后去找了10個人 ,評分分別為1-10分首先把5號拉出來,讓大家看看是不是這個人和你比哪個優(yōu)秀如果你比五號選手長得帥,那么你就不用和1-4號比了,這個區(qū)間就縮短成[5-10]如果不幸的比五號選手長得丑,那么這個區(qū)間就縮短成了[1-4]這里介紹兩個二分法的模板 主要區(qū)別在于當(dāng)前數(shù)是被劃分到左區(qū)間還是右區(qū)間模板boolcheck(int?x)?{/*?...?*/}?//?檢查x是否滿足某種性質(zhì)//?區(qū)間[l, r]被劃分成[l, mid]和[mid + 1, r]時使用:
intbsearch_1(int?l,?int?r){while?(l?????{int?mid?=?l?+?r?>>?1;if?(check(mid))?r?=?mid;????//?check()判斷mid是否滿足性質(zhì)else?l?=?mid?+?1;
????}return?l;
}//?區(qū)間[l, r]被劃分成[l, mid - 1]和[mid, r]時使用:
intbsearch_2(int?l,?int?r){while?(l?????{int?mid?=?l?+?r?+?1?>>?1;if?(check(mid))?l?=?mid;else?r?=?mid?-?1;
????}return?l;
}二分法作為一種搜索上快速的算法,可以把復(fù)雜度從O(N)變成O(log N),要滿足二分法搜索的條件是搜索區(qū)間內(nèi)滿足單調(diào)性為什么會有兩個模板呢可以看到在區(qū)分id的時候可以分為mid=(l+r)/2和(l+r)/2+1與此同時 帶來了當(dāng)前數(shù)字索引劃分區(qū)間的不同話不多說先來兩個題目試一試水69 X的平方根實現(xiàn) int sqrt(int x) 函數(shù)。計算并返回 x 的平方根,其中 x 是非負(fù)整數(shù)。由于返回類型是整數(shù),結(jié)果只保留整數(shù)的部分,小數(shù)部分將被舍去。示例 1:輸入: 4輸出: 2示例 2:輸入: 8輸出: 2說明: 8 的平方根是 2.82842...,
由于返回類型是整數(shù),小數(shù)部分將被舍去。這個題目使用二分法還是比較明顯的使用二分法搜索平方根的思想很簡單,就類似于小時候我們看的電視節(jié)目中的“猜價格”游戲,高了就往低了猜,低了就往高了猜,范圍越來越小。因此,使用二分法猜算術(shù)平方根就很自然。存在三種情況: //采用二分模板?mid劃到了左區(qū)間long?left=1;long?right=x;while(left????????????long?mid=(left+right)/2+1;if(mid*mid>x)//平方大于目標(biāo)數(shù)?往低走
????????????????????right=mid-1;else?if(mid*mid//平方大于目標(biāo)數(shù)?往低走
????????????????????left=mid;else?{//平方和恰好等于目標(biāo)數(shù)?跳出循環(huán)
????????????????????left=mid;break;
????????????}
????}return?(int)(left);74 搜索二維矩陣編寫一個高效的算法來判斷 m x n 矩陣中,是否存在一個目標(biāo)值。該矩陣具有如下特性:每行中的整數(shù)從左到右按升序排列。每行的第一個整數(shù)大于前一行的最后一個整數(shù)。輸入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 3輸出: true輸入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 13輸出: false這個題目也可以采用二分 先找一下規(guī)律發(fā)現(xiàn) 每行的第一個整數(shù)大于前一行的最后一個整數(shù) 所以這個數(shù)組 從上到下 從左到右是依次遞增的 所以我們可以采用兩次二分法第一次二分的目的是鎖定這個數(shù)在哪一行上int?left=0;
int?right=Hang-1;
while(left<right){int?mid=(left+right)/2+1;if(matrix[mid][0]>target)//當(dāng)前這個行首元素大于target?說明不可能在這一行
????????????????right=mid-1;
????????else?if(matrix[mid][0]<=target)//小于或者等于的時候?說明可能是在這一行上left=mid;
????}//最后這個left就是具體哪一行第二次二分的目的是鎖定這個數(shù)在這一行的哪一列上主要判斷索引為(Hang,mid)這個元素與target的關(guān)系Hang?=?left;
left?=0;
right=Lie-1;while(left????????int?mid=(left+right)/2+1;if(matrix[Hang][mid]>target)//如果這一行上坐標(biāo)為(Hang,mid)的元素大于target?說明目標(biāo)數(shù)可能在左邊
????????????????right=mid-1;else?if(matrix[Hang][mid]//如果這一行上坐標(biāo)為(Hang,mid)的元素小于target?說明目標(biāo)數(shù)可能在右邊
????????????????left=mid;else?//相等的話就是Truereturn?true;
}//最后找到這個數(shù)但是不一定是和目標(biāo)數(shù)相等?要判斷一下if(matrix[Hang][left]==target)return?true;else????return?false;查找元素的第一個和最后一個位置給定一個按照升序排列的整數(shù)數(shù)組 nums,和一個目標(biāo)值 target。找出給定目標(biāo)值在數(shù)組中的開始位置和結(jié)束位置。你的算法時間復(fù)雜度必須是 O(log n) 級別。如果數(shù)組中不存在目標(biāo)值,返回 [-1, -1]。輸入: nums = [5,7,7,8,8,10], target = 8輸出: [3,4]輸入: nums = [5,7,7,8,8,10], target = 6輸出: [-1,-1]因為數(shù)組已經(jīng)排過序了,我們可以使用二分查找的方法去定位左右下標(biāo)。1,使用二分法判斷是否存在目標(biāo)值2,使用二分法找到第一個?大于等于 target?的位置i3,使用二分法找到最后一個?小于等于 target的位置j這個過程類似什么 類似我們高中學(xué)過的夾逼準(zhǔn)則吧由于數(shù)組有序且從小到大排序 那么找到的[i,j]區(qū)間里必定是目標(biāo)區(qū)間 當(dāng)然還得判斷目標(biāo)區(qū)間是否存在使用二分法找到第一個?大于等于 target?的位置iint?left=0;int?right=nums.length-1;while(left<right){int?mid=(left+right)/2+1;if(nums[mid]<=target)left=mid;else???right=mid-1;
????????}使用二分法找到最后一個?小于等于 target?的位置jleft=0;right=nums.length-1;while(left<right){int?mid=(left+right)/2;if(nums[mid]>=target)right=mid;elseleft=mid+1;
}最后驗證區(qū)間是否符合我們的要求即可287 尋找重復(fù)數(shù)給定一個包含 n + 1 個整數(shù)的數(shù)組 nums,其數(shù)字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重復(fù)的整數(shù)。假設(shè)只有一個重復(fù)的整數(shù),找出這個重復(fù)的數(shù)。輸入: [1,3,4,2,2]輸出: 2輸入: [3,1,3,4,2]輸出: 3說明: 那么我們要找出這個引起質(zhì)變的數(shù)即可int?n=nums.length;int?l=0;int?r=n-1;while(l????????int?mid=(l+r)/2;int?cnt=0;for(int?i=0;i//計算1-mid?上每個數(shù)出現(xiàn)的次數(shù)if(nums[i]<=mid)
????????????????????????cnt+=1;
????????}if(cnt<=mid)//如果是每個數(shù)都出現(xiàn)了一次?那么往大找
????????????????l=mid+1;else//否則往小找
????????????????r=mid;
}return?l;162 尋找峰值峰值元素是指其值大于左右相鄰值的元素。給定一個輸入數(shù)組 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。數(shù)組可能包含多個峰值,在這種情況下,返回任何一個峰值所在位置即可。你可以假設(shè) nums[-1] = nums[n] = -∞。例 1:輸入: nums = [1,2,3,1]輸出: 2解釋: 3 是峰值元素,你的函數(shù)應(yīng)該返回其索引 2。示例 2:輸入: nums = [1,2,1,3,5,6,4]輸出: 1 或 5解釋: 你的函數(shù)可以返回索引 1,其峰值元素為 2;或者返回索引 5, 其峰值元素為 6。說明:
數(shù)組[1,2]? ? ? 它的峰值就是2? ? ? 因為1<2< -∞給大家畫一個山峰可以知道山峰的確定和他的絕對高度 無關(guān) 和他的相對高度有關(guān)只要他是比它的鄰居都高 那它就是山峰抽象成二分法怎么理解 如這個圖所示 我就比較nums[mid]和nums[mid+1]之間的關(guān)系無非就是只有兩個情況
????????????????l=mid+1;else//如果下坡了?往回走?直到找到頂峰
????????????????r=mid;
}return?l;最后推薦幾道題目,也是使用二分的,相信你看到這里也對二分有了更高的認(rèn)識,不再是有序才可以用二分Leetcode-278 第一個錯誤的版本Leetcode-275 H指數(shù)IILeetcode-35 搜索插入位置Leetcode-53 尋找旋轉(zhuǎn)排序數(shù)組中的最小值
intbsearch_1(int?l,?int?r){while?(l?????{int?mid?=?l?+?r?>>?1;if?(check(mid))?r?=?mid;????//?check()判斷mid是否滿足性質(zhì)else?l?=?mid?+?1;
????}return?l;
}//?區(qū)間[l, r]被劃分成[l, mid - 1]和[mid, r]時使用:
intbsearch_2(int?l,?int?r){while?(l?????{int?mid?=?l?+?r?+?1?>>?1;if?(check(mid))?l?=?mid;else?r?=?mid?-?1;
????}return?l;
}二分法作為一種搜索上快速的算法,可以把復(fù)雜度從O(N)變成O(log N),要滿足二分法搜索的條件是搜索區(qū)間內(nèi)滿足單調(diào)性為什么會有兩個模板呢可以看到在區(qū)分id的時候可以分為mid=(l+r)/2和(l+r)/2+1與此同時 帶來了當(dāng)前數(shù)字索引劃分區(qū)間的不同話不多說先來兩個題目試一試水69 X的平方根實現(xiàn) int sqrt(int x) 函數(shù)。計算并返回 x 的平方根,其中 x 是非負(fù)整數(shù)。由于返回類型是整數(shù),結(jié)果只保留整數(shù)的部分,小數(shù)部分將被舍去。示例 1:輸入: 4輸出: 2示例 2:輸入: 8輸出: 2說明: 8 的平方根是 2.82842...,
由于返回類型是整數(shù),小數(shù)部分將被舍去。這個題目使用二分法還是比較明顯的使用二分法搜索平方根的思想很簡單,就類似于小時候我們看的電視節(jié)目中的“猜價格”游戲,高了就往低了猜,低了就往高了猜,范圍越來越小。因此,使用二分法猜算術(shù)平方根就很自然。存在三種情況:
平方小于目標(biāo)數(shù) 往高走
平方大于目標(biāo)數(shù) 往低走
平方和恰好等于目標(biāo)數(shù) 跳出循環(huán)
????????????????????right=mid-1;else?if(mid*mid//平方大于目標(biāo)數(shù)?往低走
????????????????????left=mid;else?{//平方和恰好等于目標(biāo)數(shù)?跳出循環(huán)
????????????????????left=mid;break;
????????????}
????}return?(int)(left);74 搜索二維矩陣編寫一個高效的算法來判斷 m x n 矩陣中,是否存在一個目標(biāo)值。該矩陣具有如下特性:每行中的整數(shù)從左到右按升序排列。每行的第一個整數(shù)大于前一行的最后一個整數(shù)。輸入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 3輸出: true輸入:
matrix = [
[1, 3, 5, 7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]
target = 13輸出: false這個題目也可以采用二分 先找一下規(guī)律發(fā)現(xiàn) 每行的第一個整數(shù)大于前一行的最后一個整數(shù) 所以這個數(shù)組 從上到下 從左到右是依次遞增的 所以我們可以采用兩次二分法第一次二分的目的是鎖定這個數(shù)在哪一行上int?left=0;
int?right=Hang-1;
while(left<right){int?mid=(left+right)/2+1;if(matrix[mid][0]>target)//當(dāng)前這個行首元素大于target?說明不可能在這一行
????????????????right=mid-1;
????????else?if(matrix[mid][0]<=target)//小于或者等于的時候?說明可能是在這一行上left=mid;
????}//最后這個left就是具體哪一行第二次二分的目的是鎖定這個數(shù)在這一行的哪一列上主要判斷索引為(Hang,mid)這個元素與target的關(guān)系Hang?=?left;
left?=0;
right=Lie-1;while(left????????int?mid=(left+right)/2+1;if(matrix[Hang][mid]>target)//如果這一行上坐標(biāo)為(Hang,mid)的元素大于target?說明目標(biāo)數(shù)可能在左邊
????????????????right=mid-1;else?if(matrix[Hang][mid]//如果這一行上坐標(biāo)為(Hang,mid)的元素小于target?說明目標(biāo)數(shù)可能在右邊
????????????????left=mid;else?//相等的話就是Truereturn?true;
}//最后找到這個數(shù)但是不一定是和目標(biāo)數(shù)相等?要判斷一下if(matrix[Hang][left]==target)return?true;else????return?false;查找元素的第一個和最后一個位置給定一個按照升序排列的整數(shù)數(shù)組 nums,和一個目標(biāo)值 target。找出給定目標(biāo)值在數(shù)組中的開始位置和結(jié)束位置。你的算法時間復(fù)雜度必須是 O(log n) 級別。如果數(shù)組中不存在目標(biāo)值,返回 [-1, -1]。輸入: nums = [5,7,7,8,8,10], target = 8輸出: [3,4]輸入: nums = [5,7,7,8,8,10], target = 6輸出: [-1,-1]因為數(shù)組已經(jīng)排過序了,我們可以使用二分查找的方法去定位左右下標(biāo)。1,使用二分法判斷是否存在目標(biāo)值2,使用二分法找到第一個?大于等于 target?的位置i3,使用二分法找到最后一個?小于等于 target的位置j這個過程類似什么 類似我們高中學(xué)過的夾逼準(zhǔn)則吧由于數(shù)組有序且從小到大排序 那么找到的[i,j]區(qū)間里必定是目標(biāo)區(qū)間 當(dāng)然還得判斷目標(biāo)區(qū)間是否存在使用二分法找到第一個?大于等于 target?的位置iint?left=0;int?right=nums.length-1;while(left<right){int?mid=(left+right)/2+1;if(nums[mid]<=target)left=mid;else???right=mid-1;
????????}使用二分法找到最后一個?小于等于 target?的位置jleft=0;right=nums.length-1;while(left<right){int?mid=(left+right)/2;if(nums[mid]>=target)right=mid;elseleft=mid+1;
}最后驗證區(qū)間是否符合我們的要求即可287 尋找重復(fù)數(shù)給定一個包含 n + 1 個整數(shù)的數(shù)組 nums,其數(shù)字都在 1 到 n 之間(包括 1 和 n),可知至少存在一個重復(fù)的整數(shù)。假設(shè)只有一個重復(fù)的整數(shù),找出這個重復(fù)的數(shù)。輸入: [1,3,4,2,2]輸出: 2輸入: [3,1,3,4,2]輸出: 3說明:
不能更改原數(shù)組(假設(shè)數(shù)組是只讀的)。
只能使用額外的 O(1) 的空間。
時間復(fù)雜度小于 O(n^2) 。
數(shù)組中只有一個重復(fù)的數(shù)字,但它可能不止重復(fù)出現(xiàn)一次。
如果是 那么就說明1-x上每個數(shù)都只出現(xiàn)了一次 目標(biāo)數(shù)還得往大找
如果不是 那么說明1-x上有一個數(shù)是出現(xiàn)了兩次 目標(biāo)數(shù)得往小了找
????????????????????????cnt+=1;
????????}if(cnt<=mid)//如果是每個數(shù)都出現(xiàn)了一次?那么往大找
????????????????l=mid+1;else//否則往小找
????????????????r=mid;
}return?l;162 尋找峰值峰值元素是指其值大于左右相鄰值的元素。給定一個輸入數(shù)組 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。數(shù)組可能包含多個峰值,在這種情況下,返回任何一個峰值所在位置即可。你可以假設(shè) nums[-1] = nums[n] = -∞。例 1:輸入: nums = [1,2,3,1]輸出: 2解釋: 3 是峰值元素,你的函數(shù)應(yīng)該返回其索引 2。示例 2:輸入: nums = [1,2,1,3,5,6,4]輸出: 1 或 5解釋: 你的函數(shù)可以返回索引 1,其峰值元素為 2;或者返回索引 5, 其峰值元素為 6。說明:
你的解法應(yīng)該是 O(logN) 時間復(fù)雜度的。
數(shù)組[1,2]? ? ? 它的峰值就是2? ? ? 因為1<2< -∞給大家畫一個山峰可以知道山峰的確定和他的絕對高度 無關(guān) 和他的相對高度有關(guān)只要他是比它的鄰居都高 那它就是山峰抽象成二分法怎么理解 如這個圖所示 我就比較nums[mid]和nums[mid+1]之間的關(guān)系無非就是只有兩個情況
nums[mid]?也就是右邊的元素大于左邊的 那從左往右看就是上坡 上坡路必定存在一個頂峰
nums[mid]>nums[mid+1]?也就是右邊的元素小于等于左邊的 那從右往左看就是一個平滑的下坡,那這個頂峰必定是在mid這個位置之前,不然我也不可能有下坡的空間
????????????????l=mid+1;else//如果下坡了?往回走?直到找到頂峰
????????????????r=mid;
}return?l;最后推薦幾道題目,也是使用二分的,相信你看到這里也對二分有了更高的認(rèn)識,不再是有序才可以用二分Leetcode-278 第一個錯誤的版本Leetcode-275 H指數(shù)IILeetcode-35 搜索插入位置Leetcode-53 尋找旋轉(zhuǎn)排序數(shù)組中的最小值
往期精彩回顧
三月算法崗面經(jīng)
阿里筆試題兩道
掃碼關(guān)注我,加入每日一題算法交流群/秋招備戰(zhàn)群吧請備注 學(xué)校+昵稱才可以加群噢總結(jié)
以上是生活随笔為你收集整理的二分法查找平方和_面试手撕系列:二分法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 纯jsp实现评论功能_自己实现的java
- 下一篇: 打印的图片不清晰_如何调节图片kb,但又