Two classification problem routine

Posted by mtombs on Sat, 20 Nov 2021 07:26:25 +0100

Binary search routine

I haven't seen hydrology for a long time. Let's write an article on hydrology today...
Recently, I practiced the routine of two-point search to blow a wave

General outline of routine

  1. Do you know if this question is suitable for two points
    1) The target is in a continuous bounded interval (even 0~MAX, this can be achieved basically);
    2) Monotonic problem: the problem will tell you that you need to meet certain conditions, such as how many days to complete (set as d) at most, and let you seek the least goal (set as x), then the value f(x) of D must be a monotonic function, so that you can use dichotomy to remove half of the solution space;
  2. Find the monotone function f(x). I generally use count (Num, m) to represent this function;
  3. Bisection template: bisection of two branches. The side that does not meet the conditions must be reduced (for example, f (x) > d); The satisfied can be set as a new critical value (lo/hi=mid);
  4. Verify the validity of lo after exiting the loop

The reason is very convoluted. It's easy to understand when it becomes a topic

subject

lc69 sqrt()

Solve sqrt(n), which requires rounding down.

Solve according to the routine:

  1. If 0 and 1 are excluded, it can be determined that the solution is between (1, n/2); f(x)=x^2, monotonically increasing function (x > 1)
  2. f(x)=x^2
    The rest depends on the code
	class Solution {
    public int mySqrt(int x) {
        /**
            0. [0,x]Continuous integer of
            1. Monotonicity: f(x)=sqrt(x), monotonically increasing;
            2. =mid left
         */
                 // Special value judgment
        if (x == 0) {
            return 0;
        }
        if (x == 1) {
            return 1;
        }

         int lo = 0, hi = x / 2;
         while (lo < hi) {
             int mid = (hi - lo + 1) / 2 + lo;
             if (mid > x / mid) {
                 hi = mid - 1;
             } else {
                 lo = mid;
             }
         }

         return lo;
    }
}

It should be noted that the solution of f(x) should be converted to division, or it will cross the boundary. Don't ask me how I know....

lc1011

This is a standard dichotomous routine problem and an introductory problem. You can practice your hands and get familiar with the routine

  1. It can be guessed that if only one cargo is transported a day, it should at least have a carrying capacity of max (Num), otherwise it can not be completed; If you want to complete it in one day, the required carrying capacity is sum (Num), so the target X is bounded, X ∈ [max (Num), sum (Num)]; Although we don't know how to solve f(x), we can be sure that if x increases, the number of days required f(x) will inevitably decrease, otherwise it will increase, which meets the monotonicity and decrement, and it is suitable to use dichotomy;
  2. The solution of f(x) is very simple. You only need to deliver the goods on another day when cur + num [i] > m;
  3. Code template, no details, look at the code
	class Solution {
    public int shipWithinDays(int[] weights, int days) {
        int lo = 0, hi = 0;
        for (int n:weights) { //lo is the maximum weight, because it must be able to carry; hi is cumulative and can be loaded in one day
            lo = Math.max(lo, n);
            hi += n;
        }
    //x: Minimum loading capacity, f(x) number of days required for transportation; Monotone decreasing function
        while (lo < hi) {
            int m = (hi - lo) / 2 + lo;
            int cnt = count(weights, m);
            if (cnt > days) {
                //Insufficient loading capacity
                lo = m + 1;
            } else {
                //The loading capacity can be appropriately reduced to achieve the optimum
                hi = m;
            }
        }
        return lo;
    }

    private int count(int[] nums, int m) {
        int cnt = 1, //At least one day
        cur = 0;

        for (int i = 0; i < nums.length; i++) {
            if (nums[i] + cur > m) {
                cnt++;
                cur = 0;
            }
            cur += nums[i];
        }

        return cnt;
    }
}

Lc410. Maximum value of split array

Although it is marked as difficult, it is the same as the above question
The difficulty lies in understanding the meaning of the question, but it's really a dog's tongue twister...
You must have a sense of accomplishment after writing a difficult problem so simple~

  1. Continuous boundedness: in the best case, all array elements are subscripted one by one. At this time, the maximum value is max(nums), so the lower bound is max(nums). In the worst case, it is only reduced to one, and the maximum value is sum(max); It can be expected that if the maximum value of the array is increased, the number of array segmentation will inevitably decrease, and vice versa;
  2. f(x), which is the segmentation quantity;
  3. If f (x) > the condition given by the topic, the interval must be abandoned; Otherwise, optimization should continue in this range until lo==hi
	class Solution {
        public int splitArray(int[] nums, int m) {
            /** 2.Dichotomy
            Binary scene: find a number in a range of integers;
            The basis of binary search: the problem is monotonic
            That is, if you want to find element x, the defined search basis is f(x), then you must meet the requirements of F (a) > f(x), a > X
    
            1,Find the minimum value of the maximum value of the split array and set it to x;
            2. Function: f(x) is the number of divisions that x can determine
    
            At any position a, if f (a) < f (x), it proves that the number of segmentation is too small, which is less than the best scheme, which will inevitably lead to a > X;
            If f(a)=f(x), a==x cannot be determined; (the number of divisions is correct, and the division method is not unique)
    
            If f(a)=f(x)+1, and f(a-1)=f(x) (a-1 is the critical point)
            Then: x=a-1
    
            f(x)Monotonic decreasing:
            f(x) < m, x > b;
                 == m, x∈[a, b]
                 > m, x < a
            Requirements: b
             */
            int max = 0, sum = 0;
             for (int num: nums) {
                 max = Math.max(max, num);
                 sum += num;
             }
             //Left is divided into len segment (f(left)=len), and right is changed into 1 segment (f(right)=1)
             int left = max, right = sum;
            while (left < right) {
                //Currently set a (clip maximum)
                int mid = (right - left) / 2 + left;
                int splits = split(nums, mid);//Equivalent to f(x)
                if (splits < m) {
                    //The fragment is insufficient and the segmentation degree is not enough, which proves that the maximum value is too small and reduces a
                    right = mid - 1;
                } else {
                    left = mid;
                }
            }
            return left;
        }
        //Set the maximum value of a clip to max to see how many clips can be divided
        public int split(int[] nums, int max) {
            int splits = 1, cur = 0;
            for (int n: nums) {
                if (cur + n > max) {
                    //This number cannot be added. This clip ends here
                    splits++;
                    cur = 0;
                }
                cur += n;
            }
            return splits;
        }
    }

LCP 12. Xiao Zhang's question brushing plan

This question is the most difficult of these questions. As for the writing of the count() function in f(x), it can also be guessed here that the two most difficult points of the dichotomy problem are:
1) Know that this problem needs to be divided into two points;
2) Write the count() function.

No more questions, the reader will consider for himself

	class Solution {
        public int minTime(int[] time, int m) {
            /**
                Find the maximum time x to brush questions, and you can get f(x): number of days to brush questions, monotonic decreasing function
             */
             int lo = 0, //All by asking for help
             hi = 0; //Finish all the questions by yourself in one day
             for (int t: time) {
                 hi += t;
             }
             while (lo < hi) {
                 int mid = (hi - lo) / 2 + lo;
                 int cnt = count(time, mid);
                 if (cnt > m) {
                     //Insufficient time to brush questions
                     lo = mid + 1;
                 } else {
                     hi = mid;
              }
             }
    
             System.out.println(count(time, 3));
             return lo;
        }
        //t: Current maximum time per day
        public int count(int[] nums, int t) {
            //In order to minimize the time, record the maximum time spent on each round of problem brushing, and use help to reduce him
            int max = 0, cnt = 1, cur = 0;
            boolean used = false; //Have you asked for help that day
            for (int i = 0; i < nums.length; i++) {
                int n = nums[i];
                if (n + cur > t) {
                    if (!used) {
                        //Use help
                        used = true;
                        max = Math.max(max, n);
                        cur -= max;
                    } else {
                        //You can only brush it the next day
                        cnt++;
                        cur = 0;
                        used = false;
                        max = 0;
                    }
                    i--;
                    continue;
                }
                max = Math.max(max, n);
                cur += n;
            }
            return cnt;
        }
    }

My code is rough. Everyone must have a better way to write it...

summary

The two most difficult points of the dichotomy are:
1) Know that this problem needs to be divided into two points;
2) Write the count() function.

The first point is to improve the responsiveness in repeatedly brushing questions. For example, it was difficult for me to think of using and searching sets to solve problems before. After practicing some, now when I see some problems, I will feel that "it's not obvious to use xx", practice make perfect;

The second point depends on the ability of the algorithm, but it is basically a routine, and some conditions may be added.

Attach other exercises and practice by yourself:
lc875: Ke Ke, who likes bananas;
lc1482: minimum number of days required to make m bouquets
lc1552: magnetic force between two balls

Topics: Java Algorithm queue