【题目大意】
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
【分析】
排好序的一维数组二分查找的效率是O(logN),本例中是二维数组,但是有序的性质可以使得在局部,即一维状况下继续使用二分查找,通过合理的组织查找区间可以再O(NlogM)的时间内找到是否存在该值key。
记二维数组(n行m列)为
A11 A12 …… A1n …… …… …… …… An1 An2 …… Anm
则满足 :
A[i][1] <= A[i][2] <= ... <= A[i][m] ( i ∈ [1,n] )
A[1][j] <= A[2][j] <= ... <= A[n][j] ( j ∈ [1,m] )
设待查找值可能在第i行,则必有A[i][1] <= key <= A[i][m]
故
①查找key可能在的行,由于在每一列都递增,故可能的行必然连在一起,即为一个区间[top,down],在这个区间有A[i][1] <= key <= A[i][m] ( i ∈ [top,down] )
通过二分查找可得出满足要求的[top,down]
②从第top行开始查找值key,一行一行往下搜,知道down的下一行或者搜到结果。采用如下搜法:
即当前在第cur行,在cur行的搜索区间为[left,right]( A[cur][left] <= key <= A[cur][right] )。
找到cur行在[left,right]区间中<=key的最大值的位置pos,若其==key,则返回找到,否则key不可能在本行,只可能在下面若干行中。
比较 A[cur+1][pos] 和 key
若其>key,则搜索区间为第cur+1行的[left,pos-1]。
若其 <key,则搜索区间为第cur+1行的[pos+1,key]。
否则找到。
如此往下搜,直到找到或者cur==down+1终止。
由上可知复杂度为O(nlogn)。
给个oj的链接:点击打开链接
附个代码:
#include <cstdlib>
#include <string.h>
#include <vector>
#include <set>
#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn = 1024 ;
int matrix[maxn][maxn] , n , m , key ;
inline bool get(int &t)
{
bool flag = 0 ;
char c;
while(!isdigit(c = getchar())&&c!='-') if( c == -1 ) break ;
if( c == -1 ) return 0 ;
if(c=='-') flag = 1 , t = 0 ;
else t = c ^ 48;
while(isdigit(c = getchar())) t = (t << 1) + (t << 3) + (c ^ 48) ;
if(flag) t = -t ;
return 1 ;
}
/*返回第一个<=key的元素*/
int bs(int array[],int l,int r)
{
int mid ;
while (l<=r)
{
mid = (l+r) >> 1 ;
if( array[mid] > key ) r = mid-1 ;
else l = mid+1 ;
}
return r ;
}
bool query()
{
int topRow , downRow , i , j , l , r , mid , temp ;
l = 0 ; r = n-1 ;
/*找第一个<=key的*/
while (l<=r)
{
mid = (l+r) >> 1 ;
if( matrix[mid][0] > key ) r = mid-1 ;
else l = mid+1 ;
}
//[0,r]
if( r == -1 ) return false ;
if( matrix[r][0] == key ) return true ;
temp = r ;
l = 0 ; r = n-1 ;
/*找第一个>=key的*/
while (l<=r)
{
mid = (l+r) >> 1 ;
if( matrix[mid][m-1] >= key ) r = mid-1 ;
else l = mid+1 ;
}
//[l,n-1]
if( l == n ) return false ;
if( matrix[l][m-1] == key ) return true ;
r = temp ;
/*[0,r]和[l,n-1]无交集*/
if( r < l ) return false ;
topRow = l ;
downRow = r ;
/*interval is[topRow,downRow]*/
l = 0 ; r = m-1 ;
for ( i = topRow ; i <= downRow ; i++)
{
j = bs(matrix[i],l,r);
if( matrix[i][j] == key ) return true ;
if( i < downRow )
{
if( matrix[i+1][j] > key ) r = j ;
else if( matrix[i+1][j] < key ) l = j ;
else return true ;
}
}
return false ;
}
int main()
{
int i , j , k ;
while(get(n))
{
get(m);
get(key);
for ( i = 0 ; i < n ; i++)
for( j = 0 ; j < m ; j++)
get(matrix[i][j]);
printf("%s\n",query()?"Yes":"No");
}
}