How do I search for a number in a 2d array sorted left to right and top to bottom?

后端 未结 20 939
暖寄归人
暖寄归人 2020-11-22 13:03

I was recently given this interview question and I\'m curious what a good solution to it would be.

Say I\'m given a 2d array where all the numbers i

20条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-22 13:28

    The two main answers give so far seem to be the arguably O(log N) "ZigZag method" and the O(N+M) Binary Search method. I thought I'd do some testing comparing the two methods with some various setups. Here are the details:

    The array is N x N square in every test, with N varying from 125 to 8000 (the largest my JVM heap could handle). For each array size, I picked a random place in the array to put a single 2. I then put a 3 everywhere possible (to the right and below of the 2) and then filled the rest of the array with 1. Some of the earlier commenters seemed to think this type of setup would yield worst case run time for both algorithms. For each array size, I picked 100 different random locations for the 2 (search target) and ran the test. I recorded avg run time and worst case run time for each algorithm. Because it was happening too fast to get good ms readings in Java, and because I don't trust Java's nanoTime(), I repeated each test 1000 times just to add a uniform bias factor to all the times. Here are the results:

    enter image description here

    ZigZag beat binary in every test for both avg and worst case times, however, they are all within an order of magnitude of each other more or less.

    Here is the Java code:

    public class SearchSortedArray2D {
    
        static boolean findZigZag(int[][] a, int t) {
            int i = 0;
            int j = a.length - 1;
            while (i <= a.length - 1 && j >= 0) {
                if (a[i][j] == t) return true;
                else if (a[i][j] < t) i++;
                else j--;
            }
            return false;
        }
    
        static boolean findBinarySearch(int[][] a, int t) {
            return findBinarySearch(a, t, 0, 0, a.length - 1, a.length - 1);
        }
    
        static boolean findBinarySearch(int[][] a, int t,
                int r1, int c1, int r2, int c2) {
            if (r1 > r2 || c1 > c2) return false; 
            if (r1 == r2 && c1 == c2 && a[r1][c1] != t) return false;
            if (a[r1][c1] > t) return false;
            if (a[r2][c2] < t) return false;
    
            int rm = (r1 + r2) / 2;
            int cm = (c1 + c2) / 2;
            if (a[rm][cm] == t) return true;
            else if (a[rm][cm] > t) {
                boolean b1 = findBinarySearch(a, t, r1, c1, r2, cm - 1);
                boolean b2 = findBinarySearch(a, t, r1, cm, rm - 1, c2);
                return (b1 || b2);
            } else {
                boolean b1 = findBinarySearch(a, t, r1, cm + 1, rm, c2);
                boolean b2 = findBinarySearch(a, t, rm + 1, c1, r2, c2);
                return (b1 || b2);
            }
        }
    
        static void randomizeArray(int[][] a, int N) {
            int ri = (int) (Math.random() * N);
            int rj = (int) (Math.random() * N);
            a[ri][rj] = 2;
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    if (i == ri && j == rj) continue;
                    else if (i > ri || j > rj) a[i][j] = 3;
                    else a[i][j] = 1;
                }
            }
        }
    
        public static void main(String[] args) {
    
            int N = 8000;
            int[][] a = new int[N][N];
            int randoms = 100;
            int repeats = 1000;
    
            long start, end, duration;
            long zigMin = Integer.MAX_VALUE, zigMax = Integer.MIN_VALUE;
            long binMin = Integer.MAX_VALUE, binMax = Integer.MIN_VALUE;
            long zigSum = 0, zigAvg;
            long binSum = 0, binAvg;
    
            for (int k = 0; k < randoms; k++) {
                randomizeArray(a, N);
    
                start = System.currentTimeMillis();
                for (int i = 0; i < repeats; i++) findZigZag(a, 2);
                end = System.currentTimeMillis();
                duration = end - start;
                zigSum += duration;
                zigMin = Math.min(zigMin, duration);
                zigMax = Math.max(zigMax, duration);
    
                start = System.currentTimeMillis();
                for (int i = 0; i < repeats; i++) findBinarySearch(a, 2);
                end = System.currentTimeMillis();
                duration = end - start;
                binSum += duration;
                binMin = Math.min(binMin, duration);
                binMax = Math.max(binMax, duration);
            }
            zigAvg = zigSum / randoms;
            binAvg = binSum / randoms;
    
            System.out.println(findZigZag(a, 2) ?
                    "Found via zigzag method. " : "ERROR. ");
            //System.out.println("min search time: " + zigMin + "ms");
            System.out.println("max search time: " + zigMax + "ms");
            System.out.println("avg search time: " + zigAvg + "ms");
    
            System.out.println();
    
            System.out.println(findBinarySearch(a, 2) ?
                    "Found via binary search method. " : "ERROR. ");
            //System.out.println("min search time: " + binMin + "ms");
            System.out.println("max search time: " + binMax + "ms");
            System.out.println("avg search time: " + binAvg + "ms");
        }
    }
    

提交回复
热议问题