1. 程式人生 > 其它 >快排和二分

快排和二分

快排和二分

快排模板:

void qs(int q[] , int l , int r){
	if(l >= r)return ;
	
	int i = l - 1 , j = r + 1 , x = q[i + j >> 1] ;
	
	while(i < j){
		while(q[++ i ] < x) ;
		while(q[-- j ] > x) ;
		if(i < j)swap(q[i] , q[j]) ;
	}
	
	qs(q , l , j ) ;
	qs(q , j + 1 , r) ;
	
}

二分查詢:

對一個序列,(不一定是單調的),某個位置的左邊滿足某個條件但是其右邊不滿足那種條件,就可以用二分去查詢。

在做整數二分的時候,最讓人頭疼的就是分段時邊界條件的判斷。下面記錄一下我做題的思路:

舉個栗子:789. 數的範圍 - AcWing題庫

題目大意:

​ 輸出一個數字在非降序序列中出現的第一個位置和最後一個位置,若數列中沒有該數字,出“-1 -1”。

思路:

首先想第一個位置:k = getl(x) :在二分時,會有一箇中點mid = (l + r) / 2 。這時,目標x可能會出現在mid的左邊也可能出現在mid的右邊。先思考x出現在mid右邊的情況:

​ 因為我們要找x的最左邊的那個位置,所以我們需要一直將右邊界r向左邊縮:

​ 一句話,找左邊,右邊界向左縮

int getl(int x){
	
	int l = 1 , r = n ;
	
	while(l < r){
		int mid = l + r >> 1 ;
		
		if(x <= a[mid]) r = mid ;//右邊界向左邊縮
		else l = mid + 1 ;
		
	}
	return l ;
	
}

其次想最後一個位置:k = getr(x): 思路和getl類似

​ 一句話,找右邊,左邊界向右縮

int getr(int x){
	
	int l = 1 , r = n ;
	
	while(l < r){
		int mid = l + r + 1 >> 1;//注意l+1==r的邊界情況
		
		if(a[mid] <= x) l = mid ;//l向右縮
		else r = mid - 1 ;
		
	}
	return l ;
	
}

總程式碼:

#include<bits/stdc++.h>
using namespace std ;
const int N = 1e6 + 10 ;

int n , m ;
int a[N] ; 

void qs(int q[] , int l , int r){
	if(l >= r)return ;
	
	int i = l - 1 , j = r + 1 ;
	int x = q[(i + j >> 1)] ;
	
	while(i < j){
		while(q[++ i ] < x) ;
		while(q[-- j ] > x) ;
		if(i < j)swap(q[i] , q[j]) ;
	}
	
	qs(q , l , j ) ;
	qs(q , j + 1 , r) ;
	
}

int getl(int x){
	
	int l = 1 , r = n ;
	
	while(l < r){
		int mid = l + r >> 1 ;
		
		if(x <= a[mid]) r = mid ;
		else l = mid + 1 ;
		
	}
	return l ;
	
}

int getr(int x){
	
	int l = 1 , r = n ;
	
	while(l < r){
		int mid = l + r + 1 >> 1;
		
		if(a[mid] <= x) l = mid ;
		else r = mid - 1 ;
		
	}
	return l ;
	
}

void solve(){
	
	int x ;
	cin>>x ;
	
	int k = getl(x) ;
	
	if(a[k] != x){
		cout<<"-1 -1\n" ;
		return ;
	}
	
	cout<<k - 1<<" "<<getr(x) - 1 <<"\n" ;
}

int main(){
	ios::sync_with_stdio(false) ;
	
	cin>>n>>m ;
	
	for(int i = 1 ; i <= n ; i ++ )cin>>a[i] ;
	
	qs(a , 1 , n ) ;//for(int i = 1 ; i <= n ; i ++ )cout<<a[i]<<" " ;cout<<endl ;
	
	while(m -- )solve() ;
	
}