Search in offer (1) two-dimensional array of sword fingers

Keywords: less

  • Title Display
    In a two-dimensional array, each row is sorted in increasing order from left to right, and each column is sorted in increasing order from top to bottom. Please complete a function, input such a two-dimensional array and an integer, and determine whether the array contains the function.

  • Case study:
    A two-dimensional array, each row, each column is incremental sort.
    For example, the following array returns true if the number 7 is found, and false if the array 5 is found.
    1 2 8 9
    2 4 9 12
    4 7 10 13
    6 8 11 15

  • Solving violence

    • If this problem is searched by ordinary two-dimensional traversal, it can also complete the function, but it can not reflect the advantages of the original ordered two-dimensional array.
    • And if the array is very large, it will waste time and lead to timeouts.
    • This method and idea should be abandoned at the first time. If the problem of algorithm class is solved violently, it will not show its advantages at all.
  • Thinking topics
    • The orderly conditions given by the title must be used, but note that the orderliness is not pure orderliness.
    • Between rows: For the same column, the elements above are smaller than those below.
    • Between columns: For the same row, the elements in front are smaller than those in the latter.
    • But it does not mean that the number of the second row must be greater than the first row, for example, the first row can be 1,2,3,4, and the second row can be 2,3,4,5.
    • But it can be imagined that, regardless of removing any row or column, the element in the upper left corner must be the smallest, and the element in the lower right corner must be the largest.
  • Analysis topics
    • There are three situations in which a number is selected from an array, and the relationship between the number and the target number is: =, < or >.
    • If it is equal, the search is successful.
    • If the element in the array is smaller than the number to be searched, it means that the number to be searched should be on the right or below the current position.
    • If the element in the array is larger than the number to be searched, the number to be searched should be on the left or upper side of the current position.
    • But these two areas may overlap, for example, the right or the bottom will overlap in the lower right corner.
  • Solutions
    • First, determine whether the array is empty and whether there are values in the array, and whether the elements are in the array (that is, the elements are larger than the upper left corner of the array and smaller than the lower right corner of the array).
    • If the search starts at the top right corner, even if the number to be searched is not in the top right corner, a column or a row can be deleted at a time. (Elements larger than the upper right corner can exclude the row in which they are located and those smaller can exclude the column)
    • You can also start from the lower left corner, the same idea, but not from the upper left corner or the lower right corner.
  • Problem solving code
public static boolean Find(int target, int [][] array) {

        int rows = array.length;//Total number of banks
        int columns = array[0].length;//Total column number

        if( array != null && rows > 0 && columns > 0
                && target >= array[0][0] && target <= array[rows -1][columns - 1])
        {
            int row = 0;//Number of rows looped
            int column = columns - 1;//Number of columns looped

            while( row < rows && column >= 0 ) {

                //Equality returns true
                if( array[row][column] == target )
                    return true;

                //Determine whether the number is greater than the number in the upper right corner
                if( target > array[row][column] )
                {
                    ++row;//If larger, remove the comparison of the last line
                } else 
                {
                    --column;//If less than, remove the last column
                }
            }
        }
        return false;
}

Sure enough, through the operation, 280ms to 780ms exist, so there is uncertainty in this method.

  • If you think about this method carefully, you can generally think of it. Can you optimize it again? The answer is yes.
  • Algorithm optimization
    • If we add a layer of judgment after each judgment, although more than once, but once established, the remaining comparison time will be reduced by half. For large arrays, small arrays may not be as fast as above, but win in efficiency and stability.
  • Optimizing code presentation
public static boolean Find(int target, int [][] array) {

        int rows = array.length;//Total number of banks
        int columns = array[0].length;//Total column number

        if( array != null && rows > 0 && columns > 0
                && target >= array[0][0] && target <= array[rows -1][columns - 1])
        {
            int row = 0;//Number of rows looped
            int column = columns - 1;//Number of columns looped
            int rowSec;//Middle row
            int colSec;//Middle column

            while( row < rows && column >= 0 ) {

                //Equality returns true
                if( array[row][column] == target )
                    return true;

                //Determine whether the number is greater than the number in the upper right corner
                if( target > array[row][column] )
                {
                    rowSec = (int) Math.ceil((row + rows)/2);//Take the number of rows in the middle row (the average of the first and last rows is rounded up)
                    if( target > array[rowSec][column] )//Determine whether the value is greater than the value of the last column in the middle row
                        row = rowSec + 1;//If it is larger, all the above rows can be discarded, and if it is smaller, it can be solved according to the original idea.
                    else
                        ++row;//If larger, remove the comparison of the last line

                } else 
                {
                    colSec = (int) Math.floor( (column / 2) );//Take the number of columns in the middle (the average of the first and last columns is rounded down, the first column is 0)
                    if( target < array[row][colSec] )//Determine whether the value is less than the first row of the middle column number
                        column = colSec - 1;//If less than, all the columns behind the column can be discarded, and if greater than, they can be solved according to the original idea.
                    else
                        --column;//If less than, remove the last column
                }
            }
        }
        return false;
    }
  • summary
    • The average running time of the above code is about 350ms, and the deviation is not too large.
    • Comparing with the first code, a new judgement is added after each judgement, which judges the comparison of the middle row (column). Once established, it will save half of the useless comparison.
    • This is the way I can think of to optimize. If you have a better way, you are welcome to comment and exchange, and make progress together.

Posted by bmcewan on Fri, 31 May 2019 14:20:56 -0700