剑指Offer.1

剑指Offer.1

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

解法

这道题还是有点难度,当然,想通了自然就不难了,画一个图就能很好观察如何快速查找。比方说我们要在如下矩阵中找到22。根据每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序特性,我们可以构造如下解决方案:
在这里插入图片描述
具体说来就是,不断缩小待搜索矩阵,最后将目标找到。Java实现如下:


/**
 * Offer1
 * 
 * 基本思路:矩阵截取,不断选取子矩阵
 */
public class Offer1 {
    public static void main(String[] args) {
        int target = 102;
        int[][] array = {{1,2,4,6,8,10,11,13,15,17,20,22,24,27,30,32,35,36,38,39,42,44,46,47,48,49,51,54,55,56},{3,4,6,8,11,13,15,18,19,20,23,25,27,29,33,36,38,41,42,45,48,50,53,54,57,60,63,65,66,67},{5,7,8,11,14,15,17,19,21,23,24,28,31,33,36,39,41,44,47,49,52,53,56,57,60,63,66,68,71,72},{7,10,13,14,17,19,22,25,26,27,30,32,34,37,39,42,44,46,50,53,55,56,59,61,64,66,69,72,74,76},{8,12,16,17,20,21,23,26,29,31,33,35,37,40,42,45,48,49,52,55,58,59,61,63,67,69,70,74,76,79},{10,15,18,20,22,24,27,30,32,33,36,38,39,41,45,47,50,53,56,58,61,64,65,68,69,71,73,76,79,82},{13,17,20,23,24,26,28,31,34,36,38,41,42,43,48,50,53,56,58,61,64,67,68,71,73,74,75,78,81,84},{15,19,22,24,26,28,31,34,35,38,41,44,45,46,49,51,56,59,61,64,67,69,71,73,76,78,79,82,85,87},{17,20,23,26,29,30,32,37,40,42,43,47,50,53,55,56,58,62,64,66,69,72,75,78,80,81,83,86,88,90},{18,21,25,28,30,32,35,38,42,43,44,49,51,55,58,59,61,65,68,71,73,74,77,79,82,85,88,89,91,93},{20,23,28,29,33,36,37,40,43,45,47,52,55,58,60,62,63,66,70,74,76,77,79,81,85,88,89,91,93,94},{23,25,31,33,35,39,42,43,44,46,50,53,56,61,62,65,68,69,72,75,78,81,82,83,88,91,92,93,96,99},{26,27,33,34,38,40,45,48,51,53,55,56,58,64,66,69,72,75,77,80,82,84,87,88,90,93,94,95,99,101},{29,30,36,38,40,42,47,50,53,56,57,59,62,65,68,71,73,77,79,83,84,86,88,91,93,96,99,100,102,103},{32,33,39,42,44,46,49,53,56,59,62,65,68,71,72,75,77,78,80,85,87,90,92,94,96,99,101,103,105,107},{35,37,42,43,46,48,51,55,59,61,65,67,71,74,76,78,81,82,84,86,90,92,95,96,99,102,103,106,107,109},{36,39,43,46,49,50,53,58,62,65,67,70,73,76,77,79,84,87,88,90,93,96,99,102,103,106,108,111,112,115},{38,42,45,47,52,55,57,60,64,66,69,72,75,78,80,82,87,89,91,92,94,99,100,103,105,107,111,112,115,118},{39,44,48,49,55,57,60,63,66,69,72,75,78,80,82,85,89,92,94,95,98,101,102,105,108,111,112,115,116,120},{40,47,49,52,56,59,63,64,68,71,75,78,80,83,85,88,91,94,97,99,101,104,105,108,110,112,115,118,120,123},{42,50,53,55,59,62,66,67,71,73,78,81,82,86,87,90,94,97,100,101,104,106,107,109,111,114,117,120,123,126},{43,51,55,58,62,64,69,71,74,77,81,84,86,87,89,93,96,99,102,103,105,108,111,112,113,116,120,122,125,129},{45,54,56,59,65,67,72,75,76,79,84,87,90,92,94,97,99,102,104,107,108,111,114,116,119,120,122,124,127,132},{47,55,59,62,66,68,74,78,80,82,85,88,93,96,99,101,102,105,106,108,110,113,115,118,120,121,124,127,130,133},{49,56,61,65,68,70,76,81,83,85,87,91,95,99,102,103,104,106,108,110,113,116,118,121,124,127,130,133,134,137},{51,57,62,68,71,74,78,83,86,89,92,95,97,101,104,106,108,110,113,114,117,119,121,123,126,130,132,135,137,140},{53,59,65,69,73,75,81,86,88,92,95,97,100,103,107,109,111,112,115,117,120,122,125,126,129,131,133,138,141,143},{55,61,67,72,75,77,82,89,92,94,97,100,102,105,108,111,114,115,116,119,123,125,126,128,131,134,137,140,144,146},{57,63,68,74,78,81,85,90,95,98,100,101,103,107,110,114,117,119,120,123,126,129,130,133,136,138,141,144,146,149},{58,65,70,76,81,84,86,93,98,101,104,105,107,110,112,115,120,122,124,126,129,132,135,136,138,140,142,146,149,150}};        System.out.println(Find(target, array));
    }
    
    public static boolean FindHelper(int target, int[][] array, int m, int n, int starti, int startj) {
        boolean result = false;

        for (int j = startj; j < startj + n; j++) {
            /* 先找是否相等 */
            if(array[starti][j] == target){
                result = true;
                break;
            }
            /* 在非端点处找target区间 */
            else if(j >= startj && j < startj + n - 1){
                int endElem = array[starti][startj + n - 1];
                if(array[starti][j] < target && target < array[starti][j + 1] || target > endElem){
                    if(target > endElem){
                        j = startj + n - 1;
                    }
                    /* 说明不可能在array[:][i + 1 ~ n]的位置了,只可能在array[:][0] ~ array[:][i]的位置 */
                    for (int i = starti; i < starti + m; i++) {
                        if(array[i][j] == target){
                            result = true;
                            break;
                        }
                         /* 在非上下端点处找target区间 */
                        else if(i >= starti && i < starti + m - 1){
                            if(array[i][j] < target && target < array[i + 1][j]){
                                //System.out.println("i:" + i + " j:" + j + " Value: " + array[i][j]);
                                /* 说明不可能在array[j][i + 1 ~ n]的位置了,只可能在array[j + 1][0] ~ array[:][i]的位置 */
                                int newM = array.length - (i + 1);
                                int newN = j + 1;
                                int newStarti = i + 1; 
                                int newStartj = 0;
                                result = FindHelper(target, array, newM, newN, newStarti, newStartj);
                                return result;
                            }
                        }
                    }           
                    break;
                }
            }
        }
        return result;
    }

    public static boolean Find(int target, int [][] array) {
        boolean result = false;
        int m = array.length;
        int n = array[0].length;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print(array[i][j]);
                System.out.print(" ");
            }
            System.out.println("");
        }
        result = FindHelper(target, array, m, n, 0, 0);
        return result;
    }
}

有几个特殊情况需要注意:

  1. 如果搜索行时,没有找到满足array[starti][j] < target && target < array[starti][j + 1]条件的j,那么情况应该变为:(假设要在下面的矩阵中寻找102,即先在最后一列找101<102<103,然后直接截取黄色部分的矩阵继续搜索);
    在这里插入图片描述
  2. 那么如果搜索列时没有找到满足array[i][j] < target && target < array[i + 1][j]i,那么target要么小于这一列的最后一个元素,这样一来根据矩阵的特性,就没有解了;要么target大于这一列的最后一个元素,但是,由于这个矩阵是我们已经截取的,也就是说,就算target大,但是在外部也是无解的,所以不用对其做出处理。

结果

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值