Dichotomous answer summary

The answer is half inside binary search more difficult questions, that is, find a direct value most difficult, but we can easily make the determination of the solution space issues, such as can not, okay, big or small, return true or false, thereby reducing the solution space, keep in mind that this method has a prerequisite is to have monotonically increasing or decreasing nature, can be used. This is the binary search conditions of use;

Wood Cut

Some wood, the wood now wants to cut some of these small pieces of wood of the same length, the number of small pieces need to be at least  k. Of course, we hope to get small pieces as long as possible, you need to calculate the maximum length of the small pieces of wood can get.

Example

Sample 1

输入:
L = [232, 124, 456]
k = 7
输出: 114
Explanation: 我们可以把它分成114cm的7段,而115cm不可以

Ideas: immediate demand, relatively hard to find, but we can break down two space;

K 800  400  ..... 8 7 6

L 1   2 ......      x-1 x x+1

That is, if L continues to increase, then the block can be cut out at reduced, then there is a relationship between the increment and decrement, L, the smaller the K; and vice versa;

Then you can use dichotomy; to solving a problem most value, is determined to become a problem;

public class Solution {
    /**
     * @param L: Given n pieces of wood with length L[i]
     * @param k: An integer
     * @return: The maximum length of the small pieces
     */
    public int woodCut(int[] L, int k) {
        if(L == null || L.length == 0 || k <= 0) {
            return 0;
        }
        int maxlen = 0;
        for(int i = 0; i < L.length; i++) {
            maxlen = Math.max(maxlen, L[i]);
        }
        int start = 0; int end = maxlen;
        
        while(start + 1 < end) {
            int mid = start + (end - start) / 2;
            if(canCut(L, mid) >= k){
                start = mid;
            } else {
                end = mid;
            }
        }
        
        if(canCut(L, end) < k) {
            return start;
        }
        return end;
    }
    
    private int canCut(int[] L, int s) {
        int count = 0;
        for(int i = 0; i < L.length; i++) {
            count += L[i]/s;
        }
        return count;
    }
}

Copy Books

Given  n the book, the  i pages of this book is  pages[i]now there is  k someone to copy these books, and each person can only copy of the book for a number of consecutive, such a person may copy  pages[0], pages[1], pages[2], but we can not just copy  pages[0], pages[2], pages[3] without copying  pages[1].

Everyone copying speed is the same, a copy takes over a minute, and all at the same start copying. This is how to allocate  k the individual mandate, makes this  n book can be copied finished as soon as possible?

Returns the number of minutes to complete the task requires a minimum of copying.

Example

Example 1:

输入: pages = [3, 2, 4], k = 2
输出: 5
解释: 第一个人复印前两本书, 耗时 5 分钟. 第二个人复印第三本书, 耗时 4 分钟.

Sample 2:

输入: pages = [3, 2, 4], k = 3
输出: 4
解释: 三个人各复印一本书.

Challenge

The time complexity of O (nk)

Ideas:

Half the answer, not seeking direct request, then we ask, if you give an infinite number of people, how long you need? Max (Length of page [i]), if you give one person, how long you need, sum (Pages [i]), then the question is, you need to give your k required under personal circumstances, how long you need. Obviously, this is a gradual increase and decrease of the relationship;

The more people, the less time is required, the more people, the less time required;

public class Solution {
    /**
     * @param pages: an array of integers
     * @param k: An integer
     * @return: an integer
     */
    public int copyBooks(int[] pages, int k) {
        if(pages == null || pages.length == 0 || k <= 0) {
            return 0;
        }
        int upper = 0;
        int lower = 0;
        for(int i = 0; i < pages.length; i++) {
            upper += pages[i];
            lower = Math.max(lower, pages[i]);
        }
        
        int start = lower, end = upper;
        while(start + 1 < end) {
            int mid = start + (end - start) / 2;
            if(canCopy(pages, mid) > k) {
                start = mid;
            } else {
                // canCopy(pages, mid) <= k;
                end = mid;
            }
        }
        
        if(canCopy(pages, start) > k) {
            return end;
        }
        return start;
    }
    
    private int canCopy(int[] pages, int timelimit) {
        int count = 0;
        int sum = 0;
        int i = 0;
        while(i < pages.length) {
            // 用sum + pages[i]来判断下一个是否满足条件;
            while(i < pages.length && sum + pages[i] <= timelimit) {
                sum += pages[i];
                i++;
            }
            count++;
            sum = 0;
        }
        return count;
    }
}

Copy Books II

Given  n books, each book has the same number of pages. Now there is  k someone to copy these books. The first of  i individual needs  times[i] minutes to copy a book. Everyone can be any number of copies of the book. This is how to allocate  k individual tasks, making this  n book can be copied finished as soon as possible?

Returns the number of minutes to complete the task requires a minimum of copying.

Example

Example 1:

输入: n = 4, times = [3, 2, 4]
输出: 4
解释: 第一个人复印 1 本书, 花费 3 分钟. 第二个人复印 2 本书, 花费 4 分钟. 第三个人复印 1 本书, 花费 4 分钟.

Ideas: the idea is half the answer, I follow very similar, within a given time T, can finish with K N personal copy of this book, if K is constant, the smaller the T, then the copy of the book will <N, if the larger T, the number of books copied on> N. CopyBooks is at timelimit, everyone desperately transcription same time, see how much of this can be copied and then compared with N, in order to determine the time is more or less.

public class Solution {
    /**
     * @param n: An integer
     * @param times: an array of integers
     * @return: an integer
     */
    public int copyBooksII(int n, int[] times) {
        if(n < 0 || times == null || times.length == 0) {
            return 0;
        }
        
        // 求速度最慢的人,也就是时间花的最多的人;
        int max = times[0]; 
        for(int i = 1; i < times.length; i++) {
            max = Math.max(max, times[i]);
        }
        
        int start = 1; 
        int end = n * max; // 最慢的一个人去抄N本书;
        while(start + 1 < end) {
            int mid = start + (end - start) / 2;
            if(copyBooks(times, mid) >= n) {
                end = mid;
            } else {
                start = mid;
            }
        }
        if(copyBooks(times, start) < n) {
            return end;
        }
        return start;
    }
    
    private int copyBooks(int[] times, int timelimit) {
        int count = 0;
        for(int i = 0; i < times.length; i++) {
            count += timelimit / times[i];
        }
        return count;
    }
}

Sqrt(x)

Achieve  int sqrt(int x) the function, and returns the calculated  x  square root.

Example

样例 1:
	输入:  0
	输出: 0


样例 2:
	输入: 3
	输出: 1
	
	样例解释:
	返回对x开根号后向下取整的结果。

样例 3:
	输入: 4
	输出: 2

Idea: binary search, pay attention to judgment and long 0 to prevent overflow; standard templates written.

public class Solution {
    /**
     * @param x: An integer
     * @return: The sqrt of x
     */
    public int sqrt(int x) {
        if(x < 0) {
            return -1;
        }
        if(x == 0) {
            return 0;
        }
        
        long start = 1; long end = x; // long防止溢出;
        while(start + 1 < end) {
            long mid = start + (end - start) / 2;
            if(mid * mid > x) {
                end = mid;
            } else {
                start = mid;
            }
        }
        
        if(end * end > x) {
            return (int)start;
        } else {
            return (int)end;
        }
    }
}

Sqrt(x) II

Realization  double sqrt(double x) and  x >= 0.
Computes and returns a value x open root.

Example

Example 1:

输入: n = 2 
输出: 1.41421356

Example 2:

输入: n = 3
输出: 1.73205081

Thinking: or two points, it is noted that special handling it, if the number belongs to (0,1), the value of end is 1.0, since 0.1 is sqrt 0.316, the range of greater than 0.1;

public class Solution {
    /**
     * @param x: a double
     * @return: the square root of x
     */
    public double sqrt(double x) {
        if(x < 0) {
            return -1;
        }
        
        if(x == 0) {
            return 0;
        }
        
        double start = 0; 
        // 数字属于(0,1)返回,上界需要取1,比如0.1 sqrt是0.3,超过了0.1;上界要超过x;
        double end = Math.max(x, 1.0);
        double eps = 1e-10;
        while(start + eps < end) {
            double mid = start + (end - start) / 2;
            
            if(mid*mid > x) {
                end = mid;
            } else {
                start = mid;
            }
        }
        
        if(end*end > x) {
            return start;
        }
        return end;
    }
}

Find the Duplicate Number

A given array  nums contains  n + 1 integers, each integer from  1 to  n (inclusive), to ensure the presence of at least one repeating integer. Assuming that only a unique integer, find the number of repeats.

Example

Example 1:

输入:
[5,5,4,3,2,1]
输出:
5

Sample 2:

输入:
[5,4,4,3,2,1]
输出:
4

Notice

1. Can not modify the array (assuming the array read only)
2. Only with additional O (1) space
3 smaller than the time complexity of O (n-2 ^)
4. repeating array only a number, but may be repeated more than once

Ideas: discover the laws, P if it is repeated the number,

If <= the number of P > P , then the number of repetition is the end = P, the number of repetition on the left;

If <= the number of P, less than P, then P = Start, the number of repeats in the right

public class Solution {
    /**
     * @param nums: an array containing n + 1 integers which is between 1 and n
     * @return: the duplicate one
     */
    public int findDuplicate(int[] nums) {
        if(nums == null || nums.length == 0) {
            return 0;
        }
        
        int min = 0; int max = 0;
        for(int i = 0; i < nums.length; i++) {
            min = Math.min(min, nums[i]);
            max = Math.max(max, nums[i]);
        }
        
        int start = min; int end = max;
        while(start + 1 < end) {
            int mid = start + (end - start) / 2;
            if(count(nums, mid) > mid) { // 注意是重复的数count是大于自己;
                end = mid;
            } else {
                // count(nums, mid) < mid;
                start = mid;
            }
        }
        
        if(count(nums, start) > start) { // 注意是重复的数count是大于自己;
            return start;
        }
        return end;
    }
    
    private int count(int[] A, int num) {
        int count = 0;
        for(int i = 0; i < A.length; i++) {
            if(A[i] <= num) {
                count++;
            }
        }
        return count;
    }
}

Maximum Average Subarray II

Given an array of integers, positive and negative. To find such a sub-array, that the length is greater than or equal  k, and the average of the maximum.

Example

Example 1:

输入:
[1,12,-5,-6,50,3]
3
输出:
15.667
解释:
 (-6 + 50 + 3) / 3 = 15.667

Example 2:

输入:
[5]
1
输出:
5.000

Notice

Ensure the size of the array> = k

Ideas: direct request, do not calculate, we find that the subject requires maximum, and average length> k, then we first regardless of the length, we ask, subarray (i, j) will be able to find the maximum number;

(Ai + .. + aj) / (j-i + 1)> = avg, this is established, then converted to (ai - avg) + .. (aj - avg)> = 0 

The question then is converted to B [i] array there, there is no B [j] - B [i], j - i + 1> = k i.e. i <= j - k + 1; such that B [j] - B [i]> = 0

Then search the solution space is a problem, the above array B can be written as a function of a canAverage, then whether there is the desire avg, k such that

Because the solution space is definitely small to large avg, it is the beginning, not the back;

There then start = mid or end = mid; 

public class Solution {
    /**
     * @param nums: an array with positive and negative numbers
     * @param k: an integer
     * @return: the maximum average
     */
    public double maxAverage(int[] nums, int k) {
        if(nums == null || nums.length == 0 || k <= 0) {
            return 0.0;
        }
        
        double min = Integer.MAX_VALUE;
        double max = Integer.MIN_VALUE;
        
        for(int i = 0; i < nums.length; i++) {
            min = Math.min(min, nums[i]);
            max = Math.max(max, nums[i]);
        }
        
        // 注意题目有double,output有精度要求,那么这里binary search就有精度要求;
        double start = min; double end = max;
        while(start + 1e-5 < end) {
            double mid = start + (end - start) / 2;
            if(canFind(nums, mid, k)){
                start = mid;
            } else {
                end = mid;
            }
        }
        
        if(canFind(nums, end, k)) {
            return end;
        }
        return start;
    }
    
    private boolean canFind(int[] nums, double T, int k) {
        double rightsum = 0.0; 
        double leftsum = 0.0; 
        double minleftsum = 0.0;
        
        // 先算[0,k-2];
        for(int j = 0; j < k -1; j++) {
            rightsum += nums[j] - T;
        }
        
        // 从第k-1开始算;也就是满足第k个了;
        for(int j = k - 1; j < nums.length; j++) {
            rightsum += nums[j] - T;
            if(rightsum - minleftsum >= 0) {
                return true;
            }
            // j - i + 1 >= k --> i <= j - k  + 1; 
            // index一定是推倒出来的,不是凭空想象的;
            leftsum += nums[j - k + 1] - T;
            minleftsum = Math.min(minleftsum, leftsum);
        }
        return false;
    }
}

 

Published 562 original articles · won praise 13 · views 170 000 +

Guess you like

Origin blog.csdn.net/u013325815/article/details/104013016