JZ1 — 二维数组中的查找

题目描述

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

解法一

最基础的解法,两重循环,暴力枚举。时间复杂度为O(m*n)

public class Solution {
    public boolean Find(int target, int [][] array) {
        if (array.length == 0 || array[0].length == 0)
            return false;
        for (int i = 0; i < array.length; i++)
            for (int j = 0; j < array[i].length; j++)
                if (array[i][j] == target)
                    return true;
        return false;
    }
}

解法二

枚举每一行,如果第一列小于或等于target,最后一列大于或等于target,则说明target有可能存在于这一行,对其进行二分查找。时间复杂度为O(m*log(n))

public class Solution {
    public boolean Find(int target, int [][] array) {
        if (array.length == 0 || array[0].length == 0)
            return false;
        for (int i = 0; i < array.length; i++) {
            if (array[i][0] <= target && array[i][array[i].length - 1] >= target) {
                int left = 0, right = array[i].length - 1, mid;
                while (left <= right) {
                    mid = left + (right - left) / 2;
                    if (array[i][mid] < target)
                        left = mid + 1;
                    else if (array[i][mid] > target)
                        right = mid - 1;
                    else
                        return true;
                }
            }
            if (array[i][0] > target)
                break;
        }
        return false;
    }
}

解法三

二分查找行号,第一个最后一列大于target的行,记为begin;二分查找行号,最后一个第0列小于target的行,记为end
beginend枚举每一行,对其进行二分查找。
时间复杂度为O(m*log(n))

public class Solution {
    public boolean Find(int target, int [][] array) {
        if (array.length == 0 || array[0].length == 0)
            return false;
        int i, begin = -1, end = -1;
        int left = 0, right = array.length - 1, mid;
        // 找到第0列最后一个小于target的数字
        while (left <= right) {
            mid = left + (right - left) / 2;
            if (array[mid][0] < target) {
                end = mid;
                left = mid + 1;
            } else if (array[mid][0] == target)
                return true;
            else
                right = mid - 1;
        }

        // 找到最后一列第一个大于target的数字
        left = 0;
        right = array.length - 1;
        while (left <= right) {
            mid = left + (right - left) / 2;
            if (array[mid][array[0].length - 1] < target)
                left = mid + 1;
            else if (array[mid][array[0].length - 1] == target)
                return true;
            else {
                begin = mid;
                right = mid - 1;
            }
        }
        if (begin == -1 || end == -1)
            return false;
        // System.out.println(begin + " " + end);
        for (i = begin; i <= end; i++) {
            // 对每一行进行二分查找
            left = 0;
            right = array[i].length - 1;
            while (left <= right) {
                mid = left + (right - left) / 2;
                if (array[i][mid] < target)
                    left = mid + 1;
                else if (array[i][mid] == target)
                    return true;
                else
                    right = mid - 1;
            }
        }
        return false;
    }
}

解法四

从左下角开始枚举,如果小于targetcol++;如果大于targetrow--
时间复杂度为O(m+n)

public class Solution {
    public boolean Find(int target, int [][] array) {
        if (array.length == 0 || array[0].length == 0)
            return false;
        int row = array.length - 1, col = 0;
        while (row >= 0 && col < array[0].length) {
            if (array[row][col] < target)
                col++;
            else if (array[row][col] > target)
                row--;
            else
                return true;
        }
        return false;
    }
}

也可以从右上角进行枚举,如果小于targetrow++;如果大于targetcol--
但是不能从左上角和右下角开始,因为左上角和右下角对于每种情况都存在两种方向的选择。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部