题目描述
有一个自定义的01矩阵(即里面的元素非0即1),矩阵的每一行都是非倒序的
目的是找到第一个出现’1’的列,返回这个列值,如果没有(即元素全为0),就返回-1
限制:
You can’t access the Binary Matrix directly. You may only access the matrix using a BinaryMatrix interface:
BinaryMatrix.get(x, y)
returns the element of the matrix at index (x, y) (0-indexed).
BinaryMatrix.dimensions()
returns a list of 2 elements [m, n], which means the matrix is m * n.
解题思路
法一: 暴力法。害,碰到这种题第一反应总是暴力法,疯狂遍历,也不用多解释了。但这题暴力法无法通过,会TLE(不过它是提示你 You made too many calls to BinaryMatrix.get().
法二: 二分搜索(官方hint1)(时间复杂度O(MlogN))
要理解这个做法,首先要对题目中的非倒序有一个正确的理解,所谓非倒序,其实是在说在每一行中,0和0放在一起,1和1放在一起,而0的那堆会放在1的那堆的左边。
补充一个对于non-decreasing
的理解:
The difference being that in an increasing sequence, for x(n) and x(n+1), x(n+1) > x(n) whereas in a non-decreasing sequence, x(n+1) >= x(n)
那么要找到满足题意的那个列,其实是在找每一行中第一个1是在哪一列出现的,最后找到列数最小的那个。那么在每一行应用二分算法就很好理解了。
class Solution {
public int leftMostColumnWithOne(BinaryMatrix binaryMatrix) {
List<Integer> dimension = binaryMatrix.dimensions();
int row = dimension.get(0);
int column = dimension.get(1);
if (row <= 0 || column <= 0)
return -1;
int res = column;
for (int i = 0; i < row; ++i) {
// binary search to find the first one
int lo = 0, hi = column - 1;
// one doesn't exist
if (binaryMatrix.get(i, hi) == 0)
continue;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (binaryMatrix.get(i, mid) == 1) {
// refer to the left part
hi = mid;
}
else {
lo = mid + 1;
}
}
res = Math.min(res, lo);
}
return (res == column)? -1 : res;
}
}
法三: 优化解(官方hint2)(时间复杂度O(M + N))
一个挺tricy的方法,见见世面,具体步骤如下:
从自定义矩阵的右上角开始(这个开始位置同样也是因为non-decreasing
的定义),
(1)如果当前位置是1,就向左移动
(2)如果当前位置是0,就向下移动
最后会产生两种出界:
(1)左出界,意味着我出界前遇到的那个1所在列就是我要找的结果
(2)下出界,意味着我一路过来遇到的最后一个1所在列就是我要找的结果
稍微分析一下这个方法的内涵,考虑任何一个位置(i, j)
- 如果它为0,那么它的左边一定不会出现1,可以直接放弃这一行去看下一行
- 如果它为1,那么要去它的左边看看是否还有更左的1
- 最左的1一定不会出现在当前行的上面,因为上一点已经检查过了(↑)
- 左出界,意味着在这一行一路过来都是1,那么出界前遇到的那个就是最左的1(其实也就是第0列
- 下出界,意味着是在遇到最左的1之后又遇到了它左边的0,然后一直往下走没能再遇到更左的1,所以只能一直向下直至出界
根据这个分析可以写出下面的代码:
public int leftMostColumnWithOne(BinaryMatrix binaryMatrix) {
List<Integer> dimension = binaryMatrix.dimensions();
int row = dimension.get(0);
int column = dimension.get(1);
if (row <= 0 || column <= 0)
return -1;
int r = 0, c = column - 1;
int res = -1;
while (r < row && c >= 0) {
if (binaryMatrix.get(r, c) == 0) {
r++;
}
else {
res = c;
c--;
}
}
return res;
}