# 二维数组中的查找(剑指Offer 04)

# 题目

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

# 示例

现有矩阵 matrix 如下:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
1
2
3
4
5
6
7

给定 target = 5,返回 true

给定 target = 20,返回 false

# 限制

  • 0 <= n <= 1000
  • 0 <= m <= 1000

# 算法

# 二分查找

因为是行和列都是排序的,我们可以使用二分查找

当当前行首尾的范围包括targer,我们在当前行中使用二分查找寻找目标target

当当前行的末尾元素小于target,我们直接返回false

export const findNumberIn2DArray = (matrix, target) => {
	if (!matrix.length || !matrix[0].length) return false;
	let start, end;
	for (let i = 0; i < matrix.length; i++) {
		start = 0;
		end = matrix[0].length - 1;
		if (matrix[i][start] > target) return false;
		if (matrix[i][start] <= target && matrix[i][end] >= target) {
			while (start <= end) {
				const mid = ~~((start + end) / 2);
				if (matrix[i][mid] === target) return true;
				else if (matrix[i][mid] > target) end = mid - 1;
				else if (matrix[i][mid] < target) start = mid + 1;
			}
		}
	}
	return false;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 线性查找

初始化一个指针指向右上角,将整个二维数组看作一个二叉搜索树(BST):二维数组的每一项的左边(看作左子树)都是小于它的值,每一项下面(看作右子树)都是大于它的值

  • 如果当前指针指向值等于target,直接返回true
  • 如果当前指针指向值小于target,行row++
  • 如果当前指针指向值大于target,列col--
  • 如果指针越界row >= matrix.lengthcol < 0,返回false

这种查找方法一定不会错过目标值target

  • 如果当前值小于target,那么当前值左侧一定都小于target,只能行row++向下查找
  • 如果当前值大于target,那么当前值下面一定都大于target,只能列col--向左查找
export const findNumberIn2DArray = (matrix, target) => {
	if (!matrix.length || !matrix[0].length) return false;
	let row = 0,
		column = matrix[0].length - 1;
	while (row < matrix.length && column >= 0) {
		const cur = matrix[row][column];
		if (cur === target) return true;
		else if (cur < target) row++;
		else if (cur > target) column--;
	}
	return false;
};
1
2
3
4
5
6
7
8
9
10
11
12