Monday, September 7, 2015

First Bad Version [LeetCode]

Problem Description
You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.
You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.
Solution
This is a typical example of type of binary search that does not return immediately after finding the satisfied element.
Suppose we have 2 pointers start and end. We take middle = (start + end) / 2. Now we check if middle is a bad version. If it is yes, we do not stop here, but we will search on the left, in order to find out that whether there is some smaller bad version. By going to the left, we set end = middle - 1. So if we find nothing on the left, we return end + 1, because it is the last time we saw a bad version. If middle is not a bad version, we simply go to the right by setting start = middle + 1.

One thing to note is that in some programming language, to avoid overflow, we use (end-start)/2 + start instead of (start + end)/2
I. Python Code
# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):

class Solution(object):
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        start, middle, end = 1, 1, n
        while start <= end:
            middle = (start + end) >> 1
            if isBadVersion(middle): end = middle - 1
            else: start = middle + 1
        return end + 1
II. Java Code
/* The isBadVersion API is defined in the parent class VersionControl.
      boolean isBadVersion(int version); */

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int start = 1;
        int end = n;
        int middle;
        while(start <= end){
            middle = ((end - start)>>1) + start;
            if (isBadVersion(middle)) end = middle - 1;
            else start = middle + 1;
        }
        return end + 1;
    }
}
III. C++ Code
// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        int start = 1;
        int end = n;
        int middle;
        while(start <= end){
            middle = ((end-start)>> 1) + start;
            if(isBadVersion(middle)) end = middle - 1;
            else start = middle + 1;
        }
        return end + 1;
    }
};
IV. Javascript Code
/**
 * Definition for isBadVersion()
 * 
 * @param {integer} version number
 * @return {boolean} whether the version is bad
 * isBadVersion = function(version) {
 *     ...
 * };
 */

/**
 * @param {function} isBadVersion()
 * @return {function}
 */
var solution = function(isBadVersion) {
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */
    return function(n) {
        var start = 1;
        var end = n;
        while(start <= end){
            var middle = ((end-start) >> 1) + start;
            if (isBadVersion(middle)) end = middle - 1;
            else start = middle + 1;
        }
        return end + 1;
    };
};

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Can you explain how does (end-start)/2 + start avoid overflow?? :)

    ReplyDelete
    Replies
    1. integer is ranging from -2147483648 to 2147483647. So when (start + end) > 2147483647, overflow will happen when you compute (end+start)/2.
      To avoid that, we use (end-start)/2 + start . since end and start are integers that greater than 0, so it guarantees that (end-start)/2 is also in integer range. on the other hand, (end-start)/2 + start = (end+start)/2 <= 2 * 2147483647 /2 = 2147483647, therefore (end-start)/2 + start never has overflow.

      Delete