今天做了一道二分題
感覺二分仍需要加強
乙個經典題目
求乙個遞增陣列裡某個數字出現次數
我們第一想法:暴力
的確可以
邊讀入邊判斷是否為我們要的那個數
這種複雜度是o(n)
有沒有更高效演算法呢?
二分!!!
我們可以二分查詢陣列中這個數出現的第乙個位置和最後乙個位置
數量不就得出來了嗎
那麼怎麼二分呢?
我們知道二分的形式無非就是
while
(lelse
}
那麼其中要不要加+1還是-1,什麼時候加呢?
我們還沒有乙個固定思路
可以先假設兩個相鄰相同元素
…… 2 2 ……
如果我們要找出現2的第乙個位置
那麼我們的a[mid]==2
我們應該修改l還是r呢?
答案當然是r
因為我們不敢修改l,一修改就可能把第乙個位置跳過了
那麼r變成啥呢?
r=mid-1 嗎?還是直接r=mid?
這裡我們選擇r=mid
因為mid可能就在第乙個數字的位置,我們不能跳過
接下來考慮是(l+r+1)>>1還是(l+r)>>1呢?
我們上面的兩個相鄰相同元素就可以用上了
如果是選用前者,那麼如果中間有兩個數,會選擇右邊的數
而我們想揪出第乙個數
得選左邊的數叭
所以我們選擇了(l+r)>>1
接下來想想如果a[mid]我們在這種情況下不能修改r,只能修改l=mid(+1)
是否要+1呢?
要!!!
因為mid位置絕對不可能是第乙個位置
所以直接可以跳過
於是乎,剩下最後的a[mid]>k時
顯然同a[mid]==k的情況
**如下
for
(l=0
,r=n;l)else
}
為啥邊界是左閉右開呢(所謂邊界就是l和r的初值,我這裡寫的是0和n,下標n是不會存在於陣列裡的)
因為我們的右邊界一定要更新!
最後的結果是看r
我也不太確定,這裡的結果用l和r都是一樣的叭
然後要取最後乙個數的話,同理
所有**如下
#include.h>
using namespace std;
int a[
10000007];
inline int
read()
while
(ch>=
'0'&&ch<=
'9')
return x;
}int
main()
}int pre,last,l,r;
for(l=
0,r=n;l)else
} pre=r;
for(l=-1
,r=n-
1;l)else
} last=l;
printf
("%d"
,last-pre+1)
;return0;
}
很多時候也會用
r+(r-l)/2防止溢位
二分查詢思想
二分查詢思想應用於對有序的陣列進行查詢操作。時間複雜度 二分查詢也稱為折半查詢,每次都能將查詢區間減半,這種折半特性演算法時間複雜度為o logn mid計算 有兩種計算中值mid的方式 l h可能出現加法溢位,也就是說加法的結果大於整形能夠表示的範圍。但是l和h都為正數,因此h l不會出現加法溢位...
二分思想小剖析
這乙個月努力沖一沖,三月份的甲級能考掉就考掉了。今天看演算法筆記看到了二分,想著二分還不簡單。看了看發現並不是?演算法筆記中有一句加粗的話是我以前在二分中從沒聽過的,大部分二分問題可以歸結為 尋找有序序列中第乙個滿足某條件的元素的位置。這句話一開始聽得不明所以,仔細一想別有洞天。比如下面的木棒切割問...
二分查詢的思想
先看看leetcode兩道相關的題目,都是二分思想的應用。leetcode 35 leetcode 34 二分思想用一句話概況就是 一看就懂,一寫就廢 花了很長時間都沒有弄得懂,每個人都是不同的寫法,新手很難從中發現規律。其實二分查詢最重要的一句話就是 查詢範圍 如何確定查詢範圍?只要確定了查詢範圍...