题目描述
给你一个n*m的矩阵,其中的元素每一行从左到右按递增顺序排序,每一列从上到下按递增顺序排序,然后给你一些数x,问这些书在不在这个矩阵中,若在,输出其列号最大的元素坐标。
输入
多组测试样例,首先两个数n,m(0<n,m<=1000)
然后n行m列的一个矩阵,其中的元素保证在32位整型范围
然后一个数cnt,表示询问数的个数(0<cnt<=100)
然后是cnt个要询问的元素
输出
如果存在,输出其列号最大的元素坐标
否则,输出“NO”
样例输入
4 4 1 2 8 9 2 4 9 12 4 7 10 13 6 8 11 15 3 7 8 14
样例输出
3 2 1 3 NO
分析:题目说 其中的元素每一行从左到右按递增顺序排序,每一列从上到下按递增顺序排序,这一点一开始我想到了二分查找。但为什么每一列从上到下按递增顺序排序?之后发现二分查找虽快,但并不使用适用此题。试联想如果要查找的数在最后一行的中间,那么二分查找也要行行遍历才行。1000行至少要1000遍,这样很容易因超时而挂掉。
那么我们可以换一种思路,充分利用题目提供的条件。也是先从第一行最后一个数开始,这个数是第一行最大的。如果要查找的数小于该数,那么进行左移,左移后看该数是否还小于对应位置的数,还小的继续左移,只有这一个方向了,下边的数大于要查找的的数,上边的数则已经查找过,肯定是小于要查找的数的。如果一直小于,直到查找到最左边界还没有结果,那么矩阵中肯定是没有这个数。
同理,我们如果从第一行开始要查找的数大于最右边的数。那么这一行的数就不用看了因为这一行从该数开始到左边的数都是小于该数的,直接跳到下一行继续查找。直到找到结果,如果最终查找到最下边界还没有结果时,那么矩阵中这个数同样也是不存在的。
所以这样查找的时间复杂度为 O(n*m)(最坏情况)
还有一点需要注意的是,本题如若运用该思路,必须用c语言写,用c++也会超时挂掉。
#include<stdio.h>
const int M=1e3+5;
long long map[M][M],n,m,x,i,j,k,num;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&map[i][j]);//读入矩阵
scanf("%d",&x);
for(i=1;i<=x;i++)
{
scanf("%d",&num);//输入要查找的数
j=1;k=m;
while(1)
{
if(j>n||k<1)//如果此时已经查找到左边界或下边界,那么输出NO结束此次查找
{
printf("NO\n");
break;
}
if(num==map[j][k])//如果查找到此数,输出对应坐标结束此次查找
{
printf("%d ",j);
printf("%d\n",k);
break;
}
else if(num<map[j][k])//如果查找数小于对应坐标数,将数左移继续查找
{
k--;
}
else//如果查找数大于对应坐标数,将数下移继续查找
{
j++;
}
}
}
}
}