[leetcode journal] search for the median divide and conquer search of two ordered arrays

Posted by djbuddhi on Sat, 01 Feb 2020 09:37:43 +0100


Today, I'd like to summarize this search related topic I wrote a few days ago:
My first thought:
Divide the two arrays (suppose A, B) into
A =>
A [0] ~ a [i] a [i] ~ a [n - I] and (0 < = I < n, n = = a.size())
B =>
B [0] ~ a [J] a [J] ~ a [n - J] and (0 < = J < m, M = = b.size())
So how to solve i, j is the key to this problem. It can be obtained through observation

Conclusion 1: the number of the first half and the second half of A and B is equal

(i - 0 + 1) + (j - 0 + 1) == (n - i - 1) + (m - j - 1)
The premise of this calculation is that i j cannot be zero, so we need to change our thinking

i. j no longer represents the following table, but a few numbers in front,
It can be seen as follows: i = 0 for 0 elements i n A, i = n for all numbers in A (similarly, j)
So the relationship is

i + j = n - i + m - j

But there's one thing we need to pay attention to when we deal with this place

j = (m + n + 1) / 2 - i

  • The first point: n must be less than m to ensure that j is greater than or equal to 0, and to speed up the calculation of small arrays
  • Second, this + 1 is critical to ensure that when m+n is an odd number, the median falls to the left. For example, if m+n == 7, then the median is at the position of 4. But if i+j is 3 without 1, then the median will fall to the right. At the same time, if m+n is an even number, the calculation of j will not be affected

Conclusion 2. When a [i] < B [J-1] | B [J] < a [I-1], it means that all the conditions are not satisfied. The former means that I should move back and increase when I am small, and the latter means that I should move forward when I am big, and these two situations will not happen at the same time. It is proved very simple. The counter evidence method assumes that both of them are true

Because a [i] < B [J-1] and B [J] > b [J-1], a [i] < B [J]
And because B [J] < a [J-1], a [J] < a [J-1] is inconsistent with the condition, which is not tenable.

Now I can code. The code I write is a bit redundant and not optimized. For special cases, I write separately and some can be combined. I will compare the official website instance code later

 double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        //the size of n1 > the size of n2
        vector<int> &n1 = nums1.size() > nums2.size() ? nums1 : nums2;
        vector<int> &m1 = nums1.size() > nums2.size() ? nums2 : nums1;
        //n,m : size of two vectors
        int n = n1.size(), m = m1.size();
        //i -> m1, j -> n1
        int i = 0, j = 0, k = (n + m + 1) / 2;
        int iMin = 0, iMax = m;
		/*
		** The above is to prepare for the solution code, and the following can be based on the value of i
		** Range bisects i
		*/
        while(iMin <= iMax){
            i = iMin + (iMax - iMin) / 2;
            j = k - i;
            //Treatment of boundary in special cases
            if(i == 0)
                if(m == 0 || m1[i] >= n1[j -1])
                    break;
                else{
                    iMin = i + 1;
                    continue;
                }            
            
            if(i == m)
                if( n1[j] >= m1[i-1])
                    break;
                else{
                    iMax = i - 1;
                    continue;
                }
            
            if(j == n)
                if(m1[i] >= n1[j -1])
                    break;
                else{
                    iMin = i + 1;
                    continue; 
                } 
              
            if(j == 0)
                if(n1[j] >= m1[i - 1])
                    break;
                else{
                    iMax = i - 1;
                    continue;   
                }
           //Normal dichotomy
            if(m1[i] >= n1[j - 1] && n1[j] >= m1[i - 1]){
                break;
            }else{
                if(m1[i] < n1[j - 1]){
                    iMin = i+1;
                }else{
                    iMax = i-1;
                }
            }
        }
      //The following code is to solve the median in the case of i/j. there are two cases: 1
      //An even number is an odd number, because an odd number is a number, an even number is two numbers, and special cases are handled (this part of code can be combined with some of the above)
        double ret = 0;
        if( (n + m) % 2 == 0){
            int min, max;
            if(i != 0 && j != 0)
                min = m1[i - 1] > n1[j -1] ? m1[i -1] : n1[j -1];
            else{
                if(i == 0) min = n1[j - 1];
                if(j == 0) min = m1[i - 1];
            }
                
            if(i != m && j != n)
                max = m1[i] < n1[j] ? m1[i] : n1[j];
            else{
                if(i == m) max = n1[j];
                if(j == n) max = m1[i];
            }
       
            ret = (double)(max + min) / 2;
        }else{
            if(i != 0 && j != 0)
                ret = m1[i - 1] > n1[j -1] ? m1[i - 1] : n1[j -1];
            else{
                if (i == 0) ret = n1[j -1];
                if (j == 0) ret = m1[i -1];
            }
        }
        return ret;
    }

I will optimize the code when I have time.

Compare official codes

 public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { // to ensure m<=n
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = halfLen - i;
            //Here, j must not be equal to 0, because the array of i is a small array
			//As mentioned above, B [J-1] > a [i] and a [I-1] > b [J] will not hold at the same time
			//To adjust the position of i
			//I < IMAX & I > Imin is only used to limit the equality, if the equality will be handled in the following cases
            if (i < iMax && B[j-1] > A[i]){
                iMin = i + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = i - 1; // i is too big
            }
            else { // i is perfect
              	//Find the maximum on the left and the minimum on the right
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; }//return directly when odd

                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }

                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }

Conclusion:
In fact, the method of this problem is not very complex, that is, binary solution. It is difficult to calculate and deduce in binary time, especially in the treatment of boundary conditions. If it is not clear at the beginning, it can also separate all special cases like me. Although redundant, it can complete the logic realization in the shortest time. It's just like the discussion of mathematical situation. In the process of merging, you can't get it wrong without merging.

Reference: https://leetcode-cn.com/problems/media-of-two-sorted-arrays/solution/xun-zhao-liang-ge-you-xu-zu-de-zhong-wei-shu-b/

Published 18 original articles, won praise 0, visited 320
Private letter follow

Topics: less