显示标签为“binary search”的博文。显示所有博文
显示标签为“binary search”的博文。显示所有博文

2015年7月23日星期四

binary search 总结

二分法比较简单, 时间复杂度为O(log n)
mid = right + (left - right) / 2 防止left right 都大时候溢出
两种二分法
1. start <= end 每次start = mid + 1 或者 end = mid - 1
2. start + 1 < end 每次 start = mid 或者 end = mid

正常情况下用1的方法, 但是如果mid+1 或者mid-1 可能会错过target的话(mid 为target) 例如Find Minimum in Rotated Sorted Array 用方法2

Search for a Range

Search Insert Position

Sqrt(x)

Search in Rotated Sorted Array

前边的题只需要mid 跟target比较 而这两道题则还需要跟左右边界比较 所以要注意跟边界相等的情况下不仅会出现 > < 还有>= <=


Find Minimum in Rotated Sorted Array
与之前不同的是如果这道题每次 Amid < A[right] -->mid - 1 = right 的话那么 可能会出现如果此时mid是最小值 但是右边界确实最大值 为了防止这种情况 每次left right 都取 mid 而不是mid +-1 但是这么取得话就不能用left <= right 了 否则会无限循环 所以这里用left + 1 < right
Find Minimum in Rotated Sorted Array II

Search a 2D Matrix

2015年6月25日星期四

Sqrt(x) leetcode

Implement int sqrt(int x).
注意这道题是返回int 的平方根 所以:
sqrt(3) = 1
sqrt(4) = 2
sqrt(5) = 2
sqrt(10) = 3
用二分法来判定 逐步找到平方根, 但是要注意的是只要符合 mid^2 <= x < (mid + 1)^2 那么mid就是x的平方根.
另外要注意的是mid^2可能溢出 所以用x/mid >= mid的形式来表示
时间复杂度是O(log(x)) 空间是O(1)
public class Solution {
    public int mySqrt(int x) {
        if (x < 0) {
            return -1;
        } else if (x == 0) {
            return 0;
        }
        int left = 1;
        int right = x;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (x / mid >= mid  && x / (mid + 1) < mid + 1 ) {
                return mid;
            } else if (x / mid < mid) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return 0;
    }
}

2015年6月8日星期一

Find Minimum in Rotated Sorted Array II leetcode

Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
The array may contain duplicates.
方法类似于Search in Rotated Sorted Array II 当mid与end相等
的情况下 把边界向左移动 同时mid也会相应的移动
exp[1,3,3] mid = 3 end = 3, end--后 end = 3 mid = 1 所以end = mid --> result是1
算法的时间复杂度变成O(n) 最坏可能O(n)

public class Solution {

    public int findMin(int[] num) {
        if (num == null || num.length == 0) {
            return -1;
        }
        int start = 0;
        int end = num.length - 1;
        int mid;
        while (start + 1 < end) {
            mid = (start + end) / 2;
            
            if (num[mid] > num[end]) {
                start = mid;
            } else if (num[mid] < num[end]){
                end = mid;
            } else {
                end--;
            }
        }
        if (num[start] < num[end]) {
            return num[start];
        } else {
            return num[end];
        }
    }
}

Find Minimum in Rotated Sorted Array leetcode

Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
Find the minimum element.
You may assume no duplicate exists in the array.


case1: mid > end 所以往mid右边找最小值
case2: mid < start mid左边找最小值
算法的时间复杂度变成O(n)

public class Solution {

    public int findMin(int[] num) {
        if (num == null || num.length == 0) {
            return -1;
        }
        int start = 0;
        int end = num.length - 1;
        int mid;
        while (start + 1 < end) {
            mid = (start + end) / 2;
            if (num[mid] >= num[end]) {//case 1
                start = mid;
            } else {//case 2
                end = mid;
            }
        }
        if (num[start] < num[end]) {
            return num[start];
        } else {
            return num[end];
        }
    }
}

2015年4月29日星期三

Convert Sorted Array to Binary Search Tree leetcode

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
选择中点构造根节点然后递归构造左子树和右子树
因为递归时候要记录一个起始位置一个终止位置, 所以构造一个helper函数
注意中点被构造成root 所以递归带入是mid-1 和mid+1 所以边界条件是start > end
时间复杂度还是一次树遍历O(n),空间复杂度是栈空间O(logn)加上结果的空间O(n),所以额外空间是O(logn),总体是O(n)。
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode sortedArrayToBST(int[] num) {
        if (num == null || num.length == 0){
            return null;
        }
        return helper(num, 0, num.length - 1);
    }
    private TreeNode helper(int[] num, int start, int end){
        if (start > end){//因为是mid-1 和mid+1 所以到最后会出现start<end 而不是等于
            return null;
        }
        int mid = (start + end)/2;
        TreeNode node = new TreeNode(num[mid]);
        node.left = helper(num, start, mid-1);
        node.right = helper(num, mid + 1, end);
        return node;
    }
}

2015年4月14日星期二

Search a 2D Matrix II

Write an efficient algorithm that searches for a value in an m x n matrix, return the occurrence of it.
This matrix has the following properties:
    * Integers in each row are sorted from left to right.
    * Integers in each column are sorted from up to bottom.
    * No duplicate integers in each row or column.
Example
Consider the following matrix:
[
    [1, 3, 5, 7],
    [2, 4, 7, 8],
    [3, 5, 9, 10]
]
Given target = 3, return 2.
Challenge
O(m+n) time and O(1) extra space
对于2d的矩阵 可以从左下角或者右上角沿着对角线找, 

例如从左下角开始找(因为从上到下和从左到右都是递增的), 如果大于target就网上走一格, 如果小于target就往下走一格

public class Solution {
    /**
     * @param matrix: A list of lists of integers
     * @param: A number you want to search in the matrix
     * @return: An integer indicate the occurrence of target in the given matrix
     */
    public int searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0){
            return 0;
        }
        if (matrix[0] == null || matrix[0].length == 0){
            return 0;
        }
        int row = matrix.length - 1;
        int column = matrix[0].length - 1;
        int m = row;
        int n = 0;
        int count = 0;
        while (m >= 0 && m <= row && n >= 0 && n <= column){
            int cur = matrix[m][n];
            if (cur == target){
                count++;
                m--;
            } else if (cur > target){
                m--;
            } else {
                n++;
            }
        }
        return count;
    }
}

Find Peak element

A peak element is an element that is greater than its neighbors.
Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.
这道题也是用二分法,如果num[mid] < num[mid+1] 说明曲线在上升趋势, peak应该在后面 所以把start指针挪到mid+1上
如果num[mid] >num[mid+1], 说明是在下降的趋势, peak在左侧 把end指针指向mid

//O(log(n))
public class Solution {
    public int findPeakElement(int[] nums) {
        int start = 0;
  int end = nums.length - 1;
  int mid;
  while (start + 1 < end) {
   mid = start + (end - start) / 2;
   if (nums[mid] < nums[mid - 1]) {
    end = mid;
   } else if (nums[mid] < nums[mid + 1]) {
       start = mid;
   } 
   else {
    return mid;
   }
  }
  if (nums[start] > nums[end]) {
   return start;
  }
  return end;

    }
}
//O(n)
public class Solution {
    public int findPeakElement(int[] nums) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        if (nums.length == 1) {
            return 0;
        }
        for (int i = 0; i < nums.length; i++) {
            if (i == 0 && nums[i] > nums[i + 1]) {
                return i;
            }
            if (i == nums.length - 1 && nums[i - 1] < nums[i]) {
                return i;
            }
            if ( i > 0 && i < nums.length - 1 && nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) {
                return i;
            }
        }
        return - 1;
    }
}

First Bad Version

The code base version is an integer and start from 1 to n. One day, someone commit a bad version in the code case, so it caused itself and the following versions are all failed in the unit tests.
You can determine whether a version is bad by the following interface: 

Java:    public VersionControl {        boolean isBadVersion(int version);    }
C++:    class VersionControl {    public:        bool isBadVersion(int version);    };
Python:    class VersionControl:        def isBadVersion(version)

Find the first bad version.
Note
You should call isBadVersion as few as possible. 
Please read the annotation in code area to get the correct way to call isBadVersion in different language. For example, Java is VersionControl.isBadVersion.
Example
Given n=5
Call isBadVersion(3), get false
Call isBadVersion(5), get true
Call isBadVersion(4), get true
return 4 is the first bad version
这道题看着很复杂, 其实就是最简单的binary search 
注意调用isBadVersion时候要用VersionControl.isBadVersion

/**
 * public class VersionControl {
 *     public static boolean isBadVersion(int k);
 * }
 * you can use VersionControl.isBadVersion(k) to judge wether 
 * the kth code version is bad or not.
*/
class Solution {
    /**
     * @param n: An integers.
     * @return: An integer which is the first bad version.
     */
    public int findFirstBadVersion(int n) {
        if (n < 1){
            return -1;
        }
        int start = 1;
        int end = n;
        while (start + 1 < end){
            int mid = start + (end - start) / 2;
            if (VersionControl.isBadVersion(mid)){
                end = mid;
            } else {
                start = mid;
            }
        }
        if (VersionControl.isBadVersion(start)){
            return start;
        } else if (VersionControl.isBadVersion(end)){
            return end;
        } else {
            return -1;
        }
    }
}

2015年4月13日星期一

Search a 2D Matrix leetcode

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.
For example,
Consider the following matrix:
[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
Given target = 3, return true.
先对矩阵的行数进行二分法查找, 找到target所在行数 再对此行二分法查找 来判断target时候存在。
这个的算法时间复杂度是O(log(rows)+log(columns))。
做这道题时候犯二了 在第一次二分法的时候先判断matrix[start][0] < target结果死活不对, 后来发现如果这么判定的话当matrix[end][0] < target 时候也会跳到start行。

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0){
            return false;
        }
        if (matrix[0] == null || matrix[0].length == 0){
            return false;
        }
        int start = 0;
        int end = matrix.length - 1;
        int row;
        while (start + 1 < end){// find the row
            int mid = start + (end - start) / 2;
            if (matrix[mid][0] == target){
                return true;
            } else if (matrix[mid][0] < target){
                start = mid;
            } else {
                end = mid;
            }
        }
        if (matrix[end][0] <= target) {
            row = end;
        } else if (matrix[start][0] <= target) {
            row = start;
        } else {
            return false;
        }
        start = 0;
        end = matrix[0].length - 1;
        while (start + 1 < end){// find the column
            int mid = start + (end - start) / 2;
            if (matrix[row][mid] == target){
                return true;
            } else if (matrix[row][mid] < target){
                start = mid;
            } else {
                end = mid;
            }
        }
        if (matrix[row][start] == target){
            return true;
        } else if (matrix[row][end] == target){
            return true;
        } else {
            return false;
        }
    }
}
第二种方法
把2d矩阵转换成1d 赋值start = 0 end = row * column -1
每个元素都可以用 matrix[position/column][position%column]来表示
然后用2分法解题
时间复杂度 O(log(row * column))
public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0){
            return false;
        }
        if (matrix[0] == null || matrix[0].length == 0){
            return false;
        }
        int row = matrix.length;
        int column = matrix[0].length;
        int start = 0;
        int end = row * column - 1;
        while (start + 1 < end){
            int mid = start + (end - start) / 2;
            int num = matrix[mid / column][mid % column];
            if (num == target){
                return true;
            } else if(num < target){
                start = mid;
            } else {
                end = mid;
            }
        }
        if (matrix[start / column][start % column] == target){
            return true;
        } else if (matrix[end / column][end % column] == target){
            return true;
        } else {
            return false;
        }
    }
}
public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0) {
            return false;
        }
        if (matrix[0] == null || matrix[0].length == 0) {
            return false;
        }
        int m = matrix.length;
        int n = matrix[0].length;
        int total = m * n;
        int start = 0;
        int end = total - 1;
        while (start <= end) {
            int mid = start + (end - start) / 2;
            if (matrix[mid/n][mid%n] == target) {
                return true;
            }
            else if (matrix[mid/n][mid%n] > target) {
                end = mid - 1;
            } else {
                start = mid + 1;
            }
        }
        return false;
    }
}

2015年4月12日星期日

Search in Rotated Sorted Array II leetcode

Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.

假设原数组是{1,2,3,3,3,3,3},那么旋转之后有可能是{3,3,3,3,3,1,2},或者{3,1,2,3,3,3,3},这样的我们判断左边缘和中心的时候都是3,如果我们要寻找1或者2,我们并不知道应该跳向哪一半。解决的办法只能是对边缘移动一步,直到边缘和中间不在相等或者相遇,这就导致了会有不能切去一半的可能。所以最坏情况(比如全部都是一个元素,或者只有一个元素不同于其他元素,而他就在最后一个)就会出现每次移动一步,总共是n步,算法的时间复杂度变成O(n)


public class Solution {
    public boolean search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return false;
        }
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] == target) {
                return true;
            }
            if (nums[mid] > nums[left]) {
                if (target >= nums[left] && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } else if (nums[mid] < nums[left]) {
                if (target <= nums[right] && target > nums[mid]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            } else {
                left++;
            }
        }
        return false;
    }
}
public class Solution {

    public boolean search(int[] A, int target) {
         if (A.length == 0 || A == null){
            return false;
        }
        int start = 0;
        int end = A.length - 1;
        while (start + 1 < end){
            int mid = start + (end - start) / 2;
            // if (A[mid] == target){
            //     return true;
            // }
            if (A[start] == A[mid]){//if start == mid 可能出现mid在第一区也可能第二区
                start++;// 所以用start++ 来判断
            } else if (A[mid] > A[start]){// case Mid1
                if (target >= A[start] && target <= A[mid]){//
                    end = mid;
                } else {
                    start = mid;
                }
            } else if (A[mid] < A[start]) { //case Mid2
                if (A[start] > target && A[mid] < target){
                    start = mid;
                } else {
                    end = mid;
                }
            } else {
                end--;
            }
        }
        if (A[start] == target){
            return true;
        } else if (A[end] == target){
            return true;
        } else {
            return false;
        }
    }
}

Search in Rotated Sorted Array leetcode

Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.

下面是rotate后的一个有序数组的图。四边形的斜边表示数组中数值的大小。
在这种情况下数组分了两部分,分别都是有序(递增)的。
当我们计算了Mid以后,有两种可能,分别用Mid1和Mid2表示。
1. 如果A[Low] < A[Mid],说明Mid落在区间1中,即图中Mid1的位置。那么,如果target小于A[Mid1],那么继续在Low和Mid1中间搜索;否则,在Mid1和High中间搜索;
2. 如果A[Low] >= A[Mid],说明Mid落在区间2中,即图中Mid2的位置。同理,如果target小于A[Mid2],那么继续在Low和Mid2中间搜索;否则,在Mid2和High中间搜索。
这样,平均地,我们每次剔除一半数据,
时间复杂度是O(logn) 空间O(1)。



public class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (target == nums[mid]) {
                return mid;
            }
            if (nums[left] <= nums[mid]) {
                if (target < nums[mid] && target >= nums[left]) {
                    right = mid -1;
                } else {
                    left = mid + 1;
                }
            } else {
                if (target > nums[mid] && target <= nums[right]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}
public class Solution {
    public int search(int[] A, int target) {
        if (A.length == 0 || A == null){
            return -1;
        }
        int start = 0;
        int end = A.length - 1;
        while (start + 1 < end){
            int mid = start + (end - start) / 2;
            if (A[mid] >= A[start]){// case Mid1
                if (target >= A[start] && target <= A[mid]){//
                    end = mid;
                } else {
                    start = mid;
                }
            } else { //case Mid2
                if (A[start] > target && A[mid] < target){
                    start = mid;
                } else {
                    end = mid;
                }
            }
        }
        if (A[start] == target){
            return start;
        } else if (A[end] == target){
            return end;
        } else {
            return -1;
        }
    }
}

Search Insert Position leetcode

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0
非常简单的一道题, 就是找相应的位置, 最后如果找不到的话 <= start 返回start > end返回end+1 在start 和end中间返回end

算法复杂度是O(logn),空间复杂度O(1)

public class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = -1;
        int right = nums.length;
        while (left + 1 < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] >= target) {
                right = mid;
            } else {
                left = mid;
            }
        }
        return right;
    }
}
public class Solution {
    public int searchInsert(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int start = 0;
        int end = nums.length - 1;
        int mid;
        while (start <= end) {
            mid = (start + end) / 2;
            if (target > nums[mid]) {
                start = mid + 1;
            } else if (target < nums[mid]) {
                end = mid - 1;
            } else {
                return mid;
            }
        }
        return start;
    }
}

Search for a Range leetcode

Given a sorted array of integers, find the starting and ending position of a given target value.
Your algorithm's runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].
这道题用两次二分法分别确定左边界和右边界
时间复杂度O(logn) 空间复杂度是O(1)

public class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = {-1, -1};
        if (nums == null || nums.length == 0) {
            return res;
        }
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        int start = 0;
        int end = nums.length - 1;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (target >= nums[mid]) {
                start= mid + 1;
            } else {
                end = mid - 1;
            }
        }
        if (left <= end) {
            res[0] = left;
            res[1] = end;
        }
        return res;
    }
}
public class Solution {
    public int[] searchRange(int[] A, int target) {
        
        int [] result = {-1,-1};
        if (A.length == 0){
            return result;
        }
        int str = 0;
        int end = A.length - 1;
        int mid;
        // search for left bound
        while (str + 1 < end){
            mid = str + (end - str) / 2;
            if (A[mid] < target){
                str = mid;
            } else if (A[mid] == target){
                end = mid;
            } else {
                end = mid;
            }
        }
        if (A[str] == target){
            result[0] = str;
        } else if (A[end] == target){
            result[0] = end;
        } else {
            result[0] = result[1] = -1;
            return result;
        }
        // search for right bound
        str = 0;
        end = A.length - 1;
        while (str + 1 < end){
            mid = str + (end - str) / 2;
            if (A[mid] < target){
                str = mid;
            } else if (A[mid] == target){
                str = mid;
            } else {
                end = mid;
            }
        }
        if (A[end] == target){
            result[1] = end;
        } else if (A[str] == target){
            result[1] = str;
        } else {
            result[0] = result[1] = -1;
            return result;
        }
        return result;
    }
}

Binary Search

For a given sorted array (ascending order) and a target number, find the first index of this number in O(log n) time complexity.
If the target number does not exist in the array, return -1.
Example
If the array is [1, 2, 3, 3, 4, 5, 10], for given target 3, return 2.
这是一个经典的binary serch的模板
 1.start+1 < end
2. mid = start + (end-start/)2
3. nums[mid] <, ==,> target 的三种情况
4. 是return start end 还是-1
class Solution {
    /**
     * @param nums: The integer array.
     * @param target: Target to find.
     * @return: The first position of target. Position starts from 0.
     */
    public int binarySearch(int[] nums, int target) {
        if (nums.length == 0){
            return -1;
        }
        int start = 0;
        int end = nums.length - 1;
        int mid;
        while (start + 1 < end){
            mid = start + (end - start) / 2;
            if (target > nums[mid]){
                start = mid;
            } else if (target < nums[mid]) {
                end = mid;
            } else {
                end = mid;
            }
        }
        if (nums[start] == target){
            return start;
        } else if (nums[end] == target){
            return end;
        } else {
            return -1;
        }
    }
}