LintCode 390.寻找峰值Ⅱ

给定一个整数矩阵 A, 它有如下特性:

相邻的整数不同
矩阵有 n 行 m 列,n和m不会小于3。
对于所有的 i < n, 都有 A[i][0] < A[i][1] && A[i][m - 2] > A[i][m - 1]
对于所有的 j < m, 都有 A[0][j] < A[1][j] && A[n - 2][j] > A[n - 1][j]
我们定义一个位置 [i,j] 是峰值, 当且仅当它满足:

A[i][j] > A[i + 1][j] && A[i][j] > A[i - 1][j] &&
A[i][j] > A[i][j + 1] && A[i][j] > A[i][j - 1]

二维二分法
根据矩阵特性 任取某一行中最大的元素不断向其四个方向中比它大的元素移动 最后一定会找到一个peak 因为这一行其它元素都比这个元素小 所以这个元素一定不会移动到这一行的另一边 在一个封闭矩形中不断移动 在边界小于内圈元素的条件下 最终移动到的位置一定就是一个peak
所以可以根据这一特性 对行和列交替进行二分 每一个二分后就在去掉了一半的区间(可能存在peak 但本题只要找到一个peak就足够了) 最终会二分为四个点 即两行两列的交汇点 判断其中为peak的点
时间复杂度计算 T(n*m) = O(n) + O(m/2) + T(n/2 * m/2) 最终时间复杂度为O(n+m)

public class Solution {
    /*
     * @param A: An integer matrix
     * @return: The index of the peak
     */
    public List<Integer> findPeakII(int[][] A) {
        // write your code here
        List<Integer> results = new ArrayList<>();
        int n = A.length;
        int m = A[0].length;
        
        int startRow = 1;
        int endRow = n - 2;
        
        int startCol = 1;
        int endCol = m - 2;
        // binary search 
        while ((startRow + 1 < endRow) || (startCol + 1 < endCol)) {
            // divide row
            if (startRow + 1 < endRow) {
            // divide row
            int midRow = startRow + (endRow - startRow) / 2;
            int indexMaxCol = findMaxInRow(A, midRow, startCol - 1, endCol + 2);
            if(isPeak(A, midRow, indexMaxCol)) {
                results.add(midRow);
                results.add(indexMaxCol);
                return results;
            } else if (A[midRow - 1][indexMaxCol] > A[midRow][indexMaxCol]) {
                endRow = midRow;
            } else {
                startRow = midRow;
            }
        }
        
        if (startCol + 1 < endCol) {
            // dived indexMaxCol
            int midCol = startCol + (endCol - startCol) / 2;
            int indexMaxRow = findMaxInCol(A, midCol, startRow - 1, endRow + 2);
            if (isPeak(A, indexMaxRow, midCol)) {
                results.add(indexMaxRow);
                results.add(midCol);
                return results;
            } else if (A[indexMaxRow][midCol - 1] > A[indexMaxRow][midCol]) {
                endCol = midCol;
            } else {
                startCol = midCol;
            }
        }
        }
        
        // now we have four points left
        // A[startRow][startCol], A[startRow][endCol], A[endRow][startCol], A[endRow][endCol]
        if (isPeak(A, startRow, startCol)) {
            results.add(startRow);
            results.add(startCol);
            return results;
        }
        
        if (isPeak(A, startRow, endCol)) {
            results.add(startRow);
            results.add(endCol);
            return results;
        } 
        
        if (isPeak(A, endRow, startCol)) {
            results.add(endRow);
            results.add(startCol);
            return results;
        }
        
        if (isPeak(A, endRow, endCol)) {
            results.add(endRow);
            results.add(endCol);
            return results;
        }
        
        return results;
    }
    
    private int findMaxInRow(int[][] A, int row, int start, int end) {
        int maxIndex = 0;
        int max = A[row][0];
        for (int i = start; i < end; i++) {
            if (A[row][i] > max) {
                max = A[row][i];
                maxIndex = i;
            }
        }
        return maxIndex;
    }
    
    private int findMaxInCol(int[][] A, int col, int start, int end) {
        int maxIndex = 0;
        int max = A[0][col];
        for (int i = start; i < end; i++) {
            if (A[i][col] > max) {
                max = A[i][col];
                maxIndex = i;
            }
        }
        return maxIndex;
    }
    
    private boolean isPeak(int[][] A, int row, int col) {
        if (row <= 0 || row >= A.length - 1) {
            return false;
        }
        
        if (col <= 0 || col >= A[0].length - 1) {
            return false;
        }
        
        if (A[row][col] > A[row][col-1] && A[row][col] > A[row-1][col] && A[row][col] > A[row+1][col] && A[row][col] > A[row][col+1]) {
            return true;
        }
        
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值