题目1384:二维数组中的查找

时间限制:1 秒

内存限制:32 兆



题目描述:

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

输入:

输入可能包含多个测试样例,对于每个测试案例,

输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和列数。

输入的第二行包括一个整数t(1<=t<=1000000):代表要查找的数字。

接下来的m行,每行有n个数,代表题目所给出的m行n列的矩阵(矩阵如题目描述所示,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。

输出:

对应每个测试案例,

输出”Yes”代表在二维数组中找到了数字t。

输出”No”代表在二维数组中没有找到数字t。

样例输入:
3 3
5
1 2 3
4 5 6
7 8 9
3 3
1
2 3 4
5 6 7
8 9 10
3 3
12
2 3 4
5 6 7
8 9 10
样例输出:
Yes
No
No

分析问题:

数据量分析:1 <= m、n <= 1000,1 <=  t <= 1000000。定义数据类型: int m, n, t;


方法一:暴力法, 遍历二维数组,每一个元素与t进行比较,时间复杂度为O(m * n), 根据暴力法编写的代码已AC。

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

int main(void)
{
     int m, n, t;
     while (scanf("%d", &m) != EOF)
     {
            scanf("%d%d", &n, &t);
           bool flag = false;
           int val;
            for (int i = 0; i < m; ++i)
            {
                   for (int j = 0; j < n; ++j)
                   {
                               scanf("%d",  &val); //简化保存操作,输入一个元素,直接与t进行比较
                               if (val == t)
                                        flag = true;
                    }
            }
           if (flag == true)          printf("Yes\n");
            else printf("No\n");
     }
     return 0;
}


方法二:充分利用二维数组行递增、列递增的特性,运用二分查找, 下面方法是找到二位数组中间小于等于t的值nums[i][j], 相等则返回true,否则nums[i][j]将二位数组分为四个部分, 时间复杂度为O(logn * logm), 时间复杂度是靠直接推的,更精确的结果需要严密的计算过程。代码已AC 。有兴趣的同学可以考虑从边开始二分,依次进行行和列二分。

(0 - i, 0  - j) 一定小于nums[i][j]

( 0 -( i - 1), (j  + 1 )- n)

((i + 1) - m, 0 - j)

(i  - m, (j + 1) - n) 一定大于nums[i][j]

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

const int N = 1000;
int nums[N][N];

bool hasValue(int row1, int row2, int col1, int col2, int t)
{
	if (row1 == row2 || col1 == col2)  return false;
        int midRow = (row1 + row2) / 2;
	
	int left = col1, right = col2 - 1;
	int mid;
	//寻找mid行小于等于t的位置
	while (left <= right)
	{
		mid = (left + right) / 2;
		if (nums[midRow][mid] > t)
			right = mid - 1;
		else
			left = mid + 1;
	}
	if (right >= col1 && nums[midRow][right] == t)
		return true;
	return hasValue(row1, midRow, right + 1, col2, t) || hasValue(midRow + 1, row2, col1, right + 1, t);	
}
int main(void)
{
	int m, n, t;
	while (scanf("%d%d%d", &m, &n, &t) != EOF)
	{
		for (int i = 0; i < m; ++i)
		{
			for (int j = 0; j < n; ++j)
				scanf("%d", &nums[i][j]);
		}
		if (hasValue(0, m, 0, n, t))
			printf("Yes\n");
		else
			printf("No\n");
	}
	return 0;
}

方法三:利用二维数组行递增、列递增的特性, 以二维数组右上角,或左下角作为起点,如以右上角元素作为起点, 如果等于t,返回true,如果小于t,则丢弃行(因为这一行最大的值已小于t),如大于t则丢弃列(因为这一列最小的值已大于t), 时间复杂度为O(m + n), 代码已AC。


#include <iostream>
#include <cstdio>
using namespace std;
const int  N = 1000;
int nums[N][N];
bool hasValue(int m, int n, int t)
{
      int i = m - 1, j = 0;
     while (i >= 0 && j < n)
     {
            if (nums[i][j] == t)
                        return true;
             else if (nums[i][j] > t)
                   --i;
              else
                     ++j;
     }
     return false;
}
int main(void)
{
     int m, n, t;
     while (scanf("%d", &m) != EOF)
     {
            scanf("%d%d", &n, &t);
           bool flag = false;
           int val;
            for (int i = 0; i < m; ++i)
            {
                   for (int j = 0; j < n; ++j)
                   {
                               scanf("%d", &nums[i][j]);
                    }
            }
           if (hasValue(m, n, t))          printf("Yes\n");
            else printf("No\n");
     }
     return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值