二維數組(矩陣)元素查找


題目描述

在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。

思考

  1. 二分查找
a1 a2 a3 a4 a5 a6
b1
c1
d1
e1
f1

總結

題目的理解錯了,錯誤的認為,矩陣滿足這樣的規律:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

其實這只是一個特例,題目只說舉證中的元素滿足“左小右大,上小下大”的特點,更一般的矩陣是這樣的:

1 2 8 9
2 4 9 12
4 7 10 13
7 8 15 15

正確理解的題目的意思以后,我編寫出了滿足題目要求的代碼。具體的思路是:遍歷每一行,對每一行進行二分查找。

package com.learn.java;

import java.util.Arrays;

/**
 * @author xzy
 * @date 2020-03-25 18:56
 * 說明:
 */
public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        int[][] array = new int[][]{
                {1, 2, 8, 9},
                {2, 4, 9, 12},
                {4, 7, 10, 13},
                {6, 8, 11, 15}
        };
        for (int i = 0; i < 40; i++) {
            System.out.println("target:" + i + " find:" + main.find(i, array));
        }
    }

    /**
     * @param target - 查找目標
     * @param array  - 查找數組
     * @return 找到:元素下標  找不到:-1
     */
    public int binarySearch(int target, int[] array) {
        // head:查找區間頭 middle:查找區間中 end:查找區間尾
        int head = 0;
        int end = array.length - 1;
        int middle = end / 2;

        //1. 不可能找得到
        if (target < array[head] || target > array[end]) {
            return -2;
        }

        //2. 二分查找
        while (head <= end) {
            if (target == array[middle]) {
                //1. 找到
                return middle;
            } else if (target < array[middle]) {
                //2.向左側繼續找
                end = middle - 1;
                middle = (end - head) / 2 + head;
            } else {
                //3.向右側繼續找
                head = middle + 1;
                middle = (end - head) / 2 + head;
            }
        }
        return -1;
    }

    public boolean find(int target, int[][] array) {
        for (int row = 0; row < array[0].length; row++) {
            if (binarySearch(target, array[row]) >= 0) {
                return true;
            }
        }
        return false;
    }
}

優化

仔細的琢磨“左小右大,上小下大”

1 2 3 9
2 4 9 12
4 7 10 13
7 8 15 15
  1. 行角度
第1行最右邊的元素,是第一行最大的。

第2行最右邊的元素,是前兩行最大的。

第3行最右邊的元素,是前三行最大的。

第4行最右邊的元素,是前四行最大的。
  1. 列角度
第1列最后一個元素,是第一列最大的。

第2列最后一個元素,是前兩列最大的。

第3列最后一個元素,是前三列最大的。

第4列最后一個元素,是前四列最大的。

新的算法思想:從行列角度出發,從第一行開始,將target與每一行最后一個元素比較,排除target不可能存在的行,同時排除target不可能存在的列。

以target == 11為例,將target與第一行最后一個元素9比較,發現target > 9,而9又是第1行最大的元素,顯然,target不可能存在於第一行。繼續將target與第二行最后一個元素12比較,發現target<12,而12又是第4列后3行中最小的元素,顯然,target不可能存在於第4列。

上述算法不斷縮小元素可能存在的范圍,范圍的縮小過程是這樣的:

  1. target > 9
1 2 3 9
2 4 9 12
4 7 10 13
7 8 15 15
  1. target < 12
2 4 9 12
4 7 10 13
7 8 15 15
  1. target > 9
2 4 9
4 7 10
7 8 15
  1. target > 10
4 7 10
7 8 15
  1. target < 15

    7 8 15
  2. target > 8

    7 8
  3. 已經沒有范圍縮小到0,可以確認,矩陣中不存在target。

利用新的思想,新的實現代碼:

public boolean find2(int target, int[][] array) {

    //rowMax:行坐標最大值 columnMax:列坐標最大值
    int rowMax = array.length - 1;
    int columnMax = array[0].length - 1;

    //空矩陣判斷
    if (rowMax < 0 || columnMax < 0) {
        return false;
    }

    //target是否有可能存在於矩陣
    if (target < array[0][0] || target > array[rowMax][columnMax]) {
        return false;
    }

    //(rowPoint,columnPoint)當前檢查元素的坐標
    int rowPoint = 0;
    int columnPoint = columnMax;
    while (rowPoint <= rowMax && columnPoint >= 0) {
        if (target == array[rowPoint][columnPoint]) {
            return true;
        } else if (target > array[rowPoint][columnPoint]) {
            //不可能在這一行
            rowPoint++;
        } else {
            //不可能在這一列
            columnPoint--;
        }
    }
    return false;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM