1. 程式人生 > 其它 >演算法題解----二分查詢(整數和浮點數)

演算法題解----二分查詢(整數和浮點數)

以前電視上有一種節目,主持人給一種商品,讓參賽者猜其價格,參賽者猜一次之後主持人會提示參賽者猜的價格是高了還是低了。

主持人會給一個價格區間,這時候如果你是參賽者你會怎麼猜呢?從主持人給的價格開始猜嗎?

這樣的效率太低了,如果主持人給的區間是1-1000,這時候的複雜度就是O(n)

如果給我的話我會從主持人給的價格中位數開始猜測,我會從500元開始猜,然後主持人說這個是高了還是低了,高了我就猜250,低了我就猜750,。

這個時候我用的方法就是二分。

首先我先來介紹整數的二分查詢

題目描述

給定一個按照升序排列的長度為n的整數陣列,以及q個查詢。

對於每個查詢,返回一個元素k的起始位置和終止位置(位置從

0開始計數)。

如果陣列中不存在該元素,則返回-1

輸入格式

第一行包含整數n和q,表示陣列長度和詢問個數。

第二行包含n個整數(均在110000範圍內),表示完整陣列。

接下來q行,每行包含一個整數k,表示一個詢問元素。

輸出格式

q行,每行包含兩個整數,表示所求元素的起始位置和終止位置。

如果陣列中不存在該元素,則返回-1

資料範圍

1n100000
1q10000
1k10000

輸入樣例:

6 3

1 2 2 3 3 4

3

4

5

輸出樣例:

3 4

5 5

-1 -1

-

int binary_search1(int l,int r)
{
    while(l<r)
    {
         
int mid = (l+r+1)/2; if(check(mid)) l = mid; else r = mid-1; } return l; }

另一種情況和上面這種很相似

不過區別是mid = (l+r)/2

if( check( mid ) ) r = mid ;

else l = mid +1 ;

int binary_search2(int l,int r)
{
    while(l<r)
    {
         int mid = (l+r)/2;
         if(check(mid)) r = mid;
         
else l = mid+1; } return l; }

再回到這題

這題是單調上升的序列

我們可以把答案區間[ l , r ] 左邊 [ 0, r ] 看成是 <= x 的 區間

右邊 [ l , n-1] 看成是 >= x 的區間

那麼我們只要兩次二分先找到l再找到r就可以了

# include <iostream>
# include <cstdio>
using namespace std;

const int N=100010;
int n,m;
int a[N];

int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    scanf("%d",&a[i]);
    while(m--)
    {
        int k;
        cin>>k;
        int l=0,r=n-1;
        while(l<r)
        {
            int mid=(l+r)/2;
            if(a[mid]>=k) r=mid;
            else l=mid+1;
        }
        if(a[l]!=k) cout<<"-1 -1"<<endl;  //如果左邊界沒有找到說明區間裡面沒有這個數
        else 
        {
            cout<<l<<" ";
            r=n-1;               //重新給右區間賦值
            while(l<r)
            {
                int mid=(l+r+1)/2;      //一定要注意這裡的+1  死記住就可以了
                if(a[mid]<=k) l=mid;
                else r=mid-1;
            }
            cout<<r<<endl;
        }
    }
}

下面就介紹一下浮點數的二分相對於整數二分來說反而簡單許多

題目描述

給定一個浮點數n,求它的三次方根。

輸入格式

共一行,包含一個浮點數n

輸出格式

共一行,包含一個浮點數,表示問題的解。

注意,結果保留6位小數。

資料範圍

-10000n10000

輸入樣例:

1000.00

輸出樣例:

10.000000

這裡由於答案只有一個,所以你用binary_search1()或者 binary_search2()都可以

而且對於mid 都取 (l+r)/2

# include <iostream>
# include <algorithm>
# include <cstdio>
using namespace std;

double n;
int main()
{
     cin>>n;
     double l = -10000.0,r=10000.0;
     while(r - l > 1e-8)    //小技巧,根據精度來確定迴圈條件
     {
           double mid = (l+r) /2 ;
           if(mid*mid*mid >= n) r=mid;
           else l = mid;
      }
       printf("%.6f",l);   //注意是輸出6位小數
}