searching in 2d array as O(n) with unsorted rows

后端 未结 3 1545
暖寄归人
暖寄归人 2021-01-19 11:54

I need to write a method that takes 2d array \'int [][] m\' and a value \'val\' and check if val is in the array in the complexity of O(n) while n defined as the num

相关标签:
3条回答
  • 2021-01-19 12:07

    Smth. like that. In case of Every number at row i is equals or smaller then every number on row i+1, than you can check only first element in each row to define a row, where required value could be. Element in unsorted row can be found only with full scan.

    This algorithm have to scan 2 full rows only, which is O(n) where n - number of rows.

    public static boolean findValTest(int[][] m, int val) {
        for (int row = 0; row < m.length; row++) {
            if (m[row][0] <= val && row != m.length - 1)
                continue;
    
            int r = row;
    
            while (r >= row - 1 && r >= 0) {
                for (int col = 0; col < m[r].length; col++)
                    if (m[r][col] == val)
                        return true;
    
                r--;
            }
    
            return false;
        }
    
        return false;
    }
    

    Test cases:

    System.out.println(findValTest(arr3, -1)); // false
    System.out.println(findValTest(arr3, 5)); // true
    System.out.println(findValTest(arr3, 7)); // true
    System.out.println(findValTest(arr3, 55)); // false
    System.out.println(findValTest(arr3, 47)); // true
    System.out.println(findValTest(arr3, 147)); // true
    System.out.println(findValTest(arr3, 200)); // false
    System.out.println(findValTest(new int[][] { { 3, 4, 5 } }, 4));   // true
    
    0 讨论(0)
  • 2021-01-19 12:17

    It is possible iff. the matrix m is a square matrix of size n x n. Core idea is inspired by oleg.cherednik's answer. As soon as we find a row in m, such that m[row][0] >= val, we know that val must be in either row row or row - 1(since the same comparison on row - 1 was false). Thus, we have to find our candidate rows (O(n)) and then analyze only those two rows (also O(n)). If m is not square, but rectangular, the algorithm has a complexity of O(n + k), where n is the number of rows and k is the number of colums in m. This leads to the following algorithm.

    public class Test {
    
      public static boolean contains(final int[][]m, final int value) {
        int candidateRow = m.length;
        for (int row = 1; row < m.length; ++row) {
          if (m[row][0] == value) {
            return true;
          }
          if (m[row][0] > value) {
            candidateRow = row;
            break;
          }
        }
    
        for (int val : m[candidateRow - 1]) {
          if (val == value) {
            return true;
          }
        }
    
        if (candidateRow < m.length) {
          for (int val : m[candidateRow]) {
            if (val == value) {
              return true;
            }
          }
        }
        return false;
      }
    
      public static void main(String[] args) {
        int [][] testArray = new int [][]{
            {   0,   2,   1,   2,   0,   5,   5,   5 },
            {  21,  21,   7,   7,   7,  21,  21,  21 },
            {  21,  21,  21,  21,  21,  21,  21,  21 },
            {  21,  21,  23,  42,  41,  23,  21,  21 },
            {  60,  56,  57,  58,  53,  52,  47,  51 },
            {  61,  65,  70,  72,  73,  78,  82,  98 },
            { 112, 121, 112, 134, 123, 100,  98, 111 },
            { 136, 136, 136, 134, 147, 150, 154, 134 }
        };
        for (int[] row : testArray) {
          for (int val : row) {
            System.out.print(contains(testArray, val) + " ");
          }
          System.out.println();
    
        }
        System.out.println();
        System.out.println();
        final int[] notInMatrix = { -1, 3, 4, 6, 8, 22, 30, 59, 71, 113, 135 };
        for (int val : notInMatrix) {
          System.out.print(contains(testArray, val) + " ");
        }
        System.out.println();
      }
    }
    

    We can improve the acutal runtime by determining the candidate lines through a binary search algorithm so that candidate lines are found in O(log(n)) instead of O(n). The asymptotical runtime will still be O(n) for square matrices and O(log(n) + k) for non-square n x k matrices. The idea for this was taken from Saeed Bolhasani's answer.

      private static int findCandidateRow(final int[][] m, final int value) {
        int lower = 0;
        int upper = m.length;
        int middle = (upper + 1) / 2;
        while (middle != m.length 
            && middle != 1
            && (m[middle][0] < value || m[middle - 1][0] > value)) {
          if (m[middle][0] < value) {
            lower = middle;
          } else {
            upper = middle;
          }
          middle = lower + (upper - lower + 1) / 2;
        }
        return middle;
      }
    
    0 讨论(0)
  • 2021-01-19 12:17

    your solution is here. i made a function that do binary search for first column. if the val find in the first column the function return true, else last period of 'l' and 'r' are benefit for us. 'r' and 'l' are always equal of have only one distance(r=l or abs(r-l)=1 ). lower bound of 'r' and 'l' are expected row that the val maybe exist in it. so we should search this row.
    O(n) for binary search is Log(n) and for row search is n. so the final O(n) will be n.code is here:

    static boolean binarySearch(int arr[][], int l, int r, int x)
    {
        if (r>=l)
        {
            int mid = l + (r - l)/2;
    
            // If the element is present at the 
            // middle itself
            if (arr[mid][0] == x)
               return true;
    
            // If element is smaller than mid, then 
            // it can only be present in left subarray
            if (arr[mid][0] > x)
               return binarySearch(arr, l, mid-1, x);
    
            // Else the element can only be present
            // in right subarray
            return binarySearch(arr, mid+1, r, x);
        }
    
        // We reach here when element is not present
        //  in array
    
        int row = Math.min(l,r);
        for(int i=0; i<arr[0].length ;i++)
          if(arr[row][i]==x)
            return true;
        return false;
    }
    
    0 讨论(0)
提交回复
热议问题