剑指Offer学习 【面试题3 :二维数组中的查找】 主对角线分治解法

学习剑指offer第三题时,想着不看答案,自己先写一种实现,看了参考答案的思路,自己用标准答案的另外一种想法,结合了分治思想,搞了一天,才搞出一版代码,感觉很happy,发个原创,供大家参考,也为了自己以后查看方便。欢迎讨论,转载请注明出处,谢谢!

public class Test03 {
    /**
     * 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
     * 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
     *
     * @param matrix 待查找的数组
     * @param number 要查找的数
     * @return 查找结果,true找到,false没有找到
     */

    // 自解思想:从主对角线array[0][0]、array[1][1]、...、array[n][n]这条线去找
    // 找到array[i][i]比number小,array[i+1][i+1]比number大
    // 则查找目标不在array[0][0]到array[i][i]的正方形区域内
    // 也不在array[i+1][i+1]到array[x-1][y-1]的长方形区域内
    // 左上和右下区域被剔除,剩余左下和右上两块,用分治法查找这两块区域
    // 可能会完全剔除左边,或者完全剔除右边,分治剩余部分即可

    public static boolean find(int[][] matrix, int number) {
        int x = matrix.length;
        int y = matrix[0].length;
        return findInMatrix(matrix, number, 0, 0, x-1, y-1);
    }

    // 用原数组,要找的数字,寻找的区域(用左上下标和右下下标表示)
    public static boolean findInMatrix(int[][] matrix, int number, int x1, int y1, int x2, int y2) {
        System.out.println("search area:("+(x1+1)+", "+(y1+1)+"), ("+(x2+1)+", "+(y2+1)+")");
        if (matrix[x1][y1] > number) {
            return false;
        }
        if (matrix[x2][y2] < number) {
            return false;
        }

        // 所有的return都是递归出口
        if (x1 == x2) {
            for (int j=y1; j<=y2; j++) {
                if (matrix[x1][j] == number) {
                    System.out.println("find: ("+(x1+1)+", "+(j+1)+")");
                    return true;
                }
            }
            return false;
        }

        if (y1 == y2) {
            for (int i=x1; i<=x2; i++) {
                if (matrix[i][y1] == number) {
                    System.out.println("find: ("+(i+1)+", "+(y1+1)+")");
                    return true;
                }
            }
            return false;
        }

        int lessI = 0, lessJ = 0;
        //从正对角线开始找,记录行标
        for (int i = x1, j = y1; i <= x2 && j <= y2; i++, j++) {
            if (matrix[i][j] == number) {
                System.out.println("find: ("+(i+1)+", "+(j+1)+")");
                return true;
            } else if (matrix[i][j] < number) {
                lessI = i;
                lessJ = j;
            } else {
                break;
            }
        }

        int iIndex = lessI+1;
        int jIndex = lessJ+1;

        if (iIndex <= x2) { //还存在左下区域
            if (findInMatrix(matrix, number, iIndex, y1, x2, lessJ)) {
                return true;
            }
        }
        if (jIndex <= y2) { //还存在右上区域
            if (findInMatrix(matrix, number, x1, jIndex, lessI, y2)) {
                return true;
            }
        }

        return false;
    }

    public static void main(String[] args) {
        int[][] array = new int[][]{
                {   1,   3,   5,   7,   9,  11,  13,  15,  17},
                {   2,   6,   6,   8,  10,  12,  14,  16,  18},
                {   3,   9,  11,  13,  15,  17,  19,  21,  23},
                {   4,  10,  12,  14,  16,  18,  20,  22,  24},
                {   5,  13,  15,  21,  41,  61,  81,  83, 101},
                {   7,  16,  18,  24,  44,  64,  84,  94, 104},
                {   9,  19,  25,  35,  55,  75,  95, 105, 115},
                {  10,  20,  30,  40,  60,  80, 100, 110, 120}
        };

        System.out.println(find(array, 5));
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值