-
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
时间限制: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; }
-
-
-