二分查找、变形及应用

[LeetCode] 35 Search Insert Position

题目

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.

测试案例

Input: [1,3,5,6], 5
Output: 2

Input: [1,3,5,6], 2
Output: 1

Input: [1,3,5,6], 7
Output: 4

Input: [1,3,5,6], 0
Output: 0

代码如下

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

[LeetCode 34] Find First and Last Position of Element in Sorted Array

题目

Given an array of integers nums sorted in ascending order, 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].

测试案例

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]

代码如下

class Solution {
    public int[] searchRange(int[] nums, int target) {        
        int[] res = new int[2];
        if(nums.length == 0){
            res[0] = res[1] = -1;
            return res;
        }
        res[0] = find(nums, target, true);
        res[1] = find(nums, target, false);
        if(res[0] >= nums.length || nums[res[0]] != target){
            res[0] = -1;
            res[1] = -1;
        }
        return res;
    }
    int find(int[] nums, int target, boolean left){
        int mid;
        int start = 0, end = nums.length - 1;
        while(start <= end){
            mid = (start + end) >> 1;
            if(nums[mid] > target){
                end = mid - 1;
            }
            else if(nums[mid] == target){
                if(left){
                    end = mid - 1;
                }
                else{
                    start = mid + 1;
                }
            }
            else{
                start = mid + 1;
            }
        }
        return left ? start : end;
    }
}

[LeetCode 153] Find Minimum in Rotated Sorted Array

题目

Suppose an array sorted in ascending order 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.

测试案例

Input: [3,4,5,1,2] 
Output: 1

Input: [4,5,6,7,0,1,2]
Output: 0

代码如下

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

[LeetCode 74] Search a 2D Matrix

题目

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.

测试案例

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
Output: true

Input:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
Output: false

思路

矩阵的特点是当进行两层循环遍历,外层为行,内层为列时,矩阵中所有元素都是递增的。所以进行如下两层二分查找:

  1. 先在第一列中进行二分。找出 target 或者找出其所有的行。当二分查找的返回值为 -1时,表示矩阵中不存在 target。
  2. 在上次二分查找返回的行中再次二分。

代码如下

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m, n;
        if((m = matrix.length) == 0 || (n = matrix[0].length) == 0){
            return false;
        }
        //在第一列中搜索,找出 target 所在的行end。
        int start = 0, end = m - 1, mid;
        while(start <= end){
            mid = (start + end) >> 1;
            if(matrix[mid][0] == target){
                return true;
            }
            else if(matrix[mid][0] > target){
                end = mid - 1;
            }
            else{                
                start = mid + 1;
            }
        }
        int pos = end;
        if(pos == -1){
            return false;
        }
        for(start = 0, end = n - 1; start <= end;){
            mid = (start + end) >> 1;
            if(matrix[pos][mid] == target){
                return true;
            }
            else if(matrix[pos][mid] > target){
                end = mid - 1;
            }
            else{
                start = mid + 1;
            }
        }
        return false;
    }
}

[LeetCode 240] Search a 2D Matrix II

题目

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 in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.

测试案例

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
Given target = 5, return true.
Given target = 20, return false.

思路

  1. 每次在矩阵的左边一列进行二叉查找,若查找到 target,返回 true。否则设查找结束后返回值为end。end = -1时,直接返回false。
  2. 取出子矩阵 [0 ~ end][1~ n - 1]。
  3. 重复上述过程共 n 次(因为每查找一次,矩阵列数减1)。
  4. 时间复杂度为 \(O(nlgm)\)。当 n > m时,先在列中进行二分查找。

代码如下

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m, n, start, end, mid;
        //初始化 m 和 n
        if((m = matrix.length) == 0 || (n = matrix[0].length) == 0){
            reutrn false;               
        }        
        //初始化start 和 mid 
        start = 0;end = m - 1;
        //进行 n 次 二分查找
        for(int i = 0; i < n; i ++){
            start = 0;
            while(start <= end){
                mid = (start + end) >> 1;
                if(matrix[mid][i] == target){
                    return true;
                }
                else if(matrix[mid][i] < target){
                    start = mid + 1;
                }
                else{
                    end = mid - 1;
                }
            }
            if(end == -1){
                break;
            }
        }        
        reutrn false;
    }
}
posted @ 2018-09-05 15:04  Echie  阅读(106)  评论(0编辑  收藏  举报