01 在递增[下面的<上面的, 左边的<右边的]二维数组中查找给定的值

前言

本博文部分图片, 思路来自于剑指offer 或者编程珠玑

问题描述

这里写图片描述

满足条件的矩阵
这里写图片描述

思路

书中给出的思路有两种
思路一 : 从第一行开始进行查找, 因为每一行的数据有序, 所以可以使用二分查找, 剪枝条件为给定的数据小于给定行的第一个数字[给定行最小的]

思路二 : 从arr[0][col-1]开始查找, arr[0][col-1]的特征为当前行的其他数据都小于该数据, 当前列的其他数据都大于该数据, 这就为我们构造了两个剪枝迭代的条件
    1 如果给定的数字大于arr[0][col-1] 则可以剪去当前行[row ++]
    2 如果给定的数字小于arr[0][col-1] 则可以剪去当前列[col –]

arr[0][col-1]
这里写图片描述

这里写图片描述

参考代码

/**
 * file name : Test22FindNumberInTwoDimen.java
 * created at : 10:48:18 AM Jun 4, 2015
 * created by 970655147
 */

package com.hx.test04;

public class Test22FindNumberInTwoDimen {

    // 从二维数组[左边的小于右边的, 上面的小于小面的]中找到一个数         from 剑指offer  page40
    public static void main(String []args) {

        int[][] arr = {
                {1, 2, 8, 9 }, 
                {2, 4, 9, 12 },
                {4, 7, 10, 13 },
                {6, 8, 11, 15 }
        };
        int tar = 11;

        findNumberInArr01(arr, tar);
        findNumberInArr02(arr, tar);
        findNumberInArr03(arr, tar);

    }

    // 思路 : 一行一行的找, 剪枝条件 : 第一个元素大于tar
    public static void findNumberInArr01(int[][] arr, int tar) {
        for(int row=0; row<arr.length; row++) {
            if(arr[row][0] > tar) {
                break ;
            } else {
                int col = binarySearch(arr[row], tar);
                if(col != -1) {
                    Log.log(row, col);
                }
            }
        }
    }

    // binarySearch
    private static int binarySearch(int[] arr, int tar) {
        int low = 0, high = arr.length - 1, mid;

        while(low <= high) {
            mid = (low + high) >> 1;
            if(arr[mid] > tar) {
                high = mid - 1;
            } else if(arr[mid] < tar) {
                low = mid + 1;
            } else {
                return mid;
            }

        }

        return -1;
    }

    // 思路 : 初始row为0, col为arr[0].length-1
    // 遍历条件 : row小于arr.length 并且col大于等于0      否则视为找不到
        // 如果当前元素小于tar  则可以剔除当前行[当前行的元素均小于当前元素]
        // 如果当前元素大于tar  则可以剔除当前列[当前列的元素均大于当前元素]
        // 否则  找到目标元素
    public static void findNumberInArr02(int[][] arr, int tar) {
        int row = 0, col = arr[0].length - 1;

        while(row < arr.length && col >= 0) {
            if(arr[row][col] > tar) {
                col --;
            } else if(arr[row][col] < tar) {
                row ++;
            } else {
                Log.log(row, col);
                break;
            }
        }
    }

    // 思路 和前面一种方法差不多, 不过初始位置不一样, 导致了逻辑有一些差别
    public static void findNumberInArr03(int[][] arr, int tar) {
        int row = arr.length - 1, col = 0;

        while(row < arr.length && col >= 0) {
            if(arr[row][col] > tar) {
                row --;
            } else if(arr[row][col] < tar) {
                col ++;
            } else {
                Log.log(row, col);
                break;
            }
        }

    }

}

效果截图

这里写图片描述

总结

对于思路一 : n * n的矩阵中, 需要计算n次二分查找, 每一次时间复杂度为log(n), 总的时间复杂度为O(nlog(n) ), 假设剪枝减掉一半, 复杂度为O((1 /2) nlog(n) ), 忽略掉常数项, 时间复杂度依然为O(nlog(n) )
对于思路二 : n * n的矩阵中, 因为每一次迭代, 都必然剪去一行, 或者一列, 所以最多的尝试次数为n次, 时间复杂度为O(n)

注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值