Chapter 2: Binary Search & Sorted Array

二分查找的前提条件是数组是完全有序或者部分有序,其时间复杂度通常为O(logn).

二分查找模板(可应对多种不同需求)

public class BinarySearchTemplate {
public int binarySearch(int[] nums, int target) {
	if (nums == null || nums.length == 0) {
		return -1;
	}
	
	int begin = 0, end = nums.length - 1;
	while (begin + 1 < end) {
		int mid = begin + (end - begin)/2;
		if (nums[mid] == target) {
			return mid; // can be modified
		}
		if (nums[mid] < target) {
			begin = mid;
		}else {
			end = mid;
		}
	}
	
	if (nums[begin] == target) {
		return begin; // can be modified
	}
	if (nums[end] == target) {
		return end; // can be modified
	}
	
	return -1;
}
}

可使用上述模板解决的问题

Problem 1: 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.

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

(leetcode: https://leetcode.com/problems/search-insert-position/)

Solution

public class Solution {
    public int searchInsert(int[] nums, int target) {
		if (nums == null || nums.length == 0) {
			return 0;
		}

		int begin = 0, end = nums.length - 1;
		while (begin + 1 < end) {
			int mid = begin + (end - begin) / 2;
			if (nums[mid] < target) {
				begin = mid;
			} else {
				end = mid;
			}
		}

		if (target <= nums[begin]) {
		    return begin;
		}
		if (target > nums[end]) {
		    return end + 1;
		}
		return end;
    }
}

 

Problem 2: Search for a Range

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].

Solution

public class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = {-1, -1};
        if (nums == null || nums.length == 0) {
			return res;
		}

		res[0] = getLowerIdx(nums, target);
		if (res[0] == -1) {
		    return res;
		}
		res[1] = getHigherIdx(nums, target);
		return res;
    }
    
    public int getLowerIdx(int[] nums, int target) {
        int begin = 0, end = nums.length - 1;
		while (begin + 1 < end) {
			int mid = begin + (end - begin) / 2;
			if (nums[mid] < target) {
				begin = mid;
			} else {
				end = mid;
			}
		}
		if (nums[begin] == target) {
			return begin; 
		}
		if (nums[end] == target) {
			return end; 
		}
		return -1;
    }
    
    public int getHigherIdx(int[] nums, int target) {
        int begin = 0, end = nums.length - 1;
		while (begin + 1 < end) {
			int mid = begin + (end - begin) / 2;
			if (nums[mid] <= target) {
				begin = mid;
			} else {
				end = mid;
			}
		}
		if (nums[end] == target) {
			return end; 
		}
		if (nums[begin] == target) {
			return begin; 
		}
		return -1;
    }
}

 

Problem 3: Search in Rotated Sorted Array

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.

 

Solution

public class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
			return -1;
		}

		int begin = 0, end = nums.length - 1;
		while (begin + 1 < end) {
			int mid = begin + (end - begin) / 2;
			if (nums[mid] == target) {
				return mid;
			}
			if (nums[mid] > target) {
			    if (target < nums[begin] && nums[mid] > nums[begin]) {
			        begin = mid;
			    } else {
			        end = mid;
			    }
			} else {
			    // note: boundary
			    if (target >= nums[begin] && nums[mid] < nums[begin]) {
			        end = mid;
			    } else {
			        begin = mid;
			    }
			}
		}

		if (nums[begin] == target) {
			return begin; 
		}
		if (nums[end] == target) {
			return end; 
		}

		return -1;
    }
}

容易错误的Case:

[5, 1, 3] , 5;

[1, 3, 5], 1;

 

Problem 4: Square Root

用最快的方法求一个数的平方根。

public class SquareRoot {
	public double getSquareRoot(double d) {
		if (d < 0) {
			return -1;
		}
		if (d == 0 || d == 1) {
			return d;
		}

		double low = 0.0;
		double high = d < 1.0 ? 1 : d;
		double epsilo = 1e-6;
		double mid = 0;

		while (true) {
			mid = low + (high - low) / 2.0;
			if (Math.abs(mid * mid - d) < epsilo) {
				break;
			}
			if (mid * mid < d) {
				low = mid;
			} else {
				high = mid;
			}
		}

		return mid;
	}
}

 

Sorted Array

Problem 1: Remove Duplicates from Sorted Array I

Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

For example,
Given input array nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the new length.

 

public class Solution {
    public int removeDuplicates(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int len = nums.length;
        int p1 = 0, p2 = 1;
        while (p2 < len) {
            if (nums[p1] != nums[p2]) {
                ++p1;
                ++p2;
                continue;
            }
            while (p2 < len && nums[p2] == nums[p1]) {
                ++p2; // find the first elem not equal to nums[p1]
            }
            if (p2 == len) {
                break;
            }
            nums[p1 + 1] = nums[p2];
            ++p1;
        }
        return p1 + 1;
    }
}

 

Problem 2: Remove Duplicates from Sorted Array II

Follow up for "Remove Duplicates":
What if duplicates are allowed at most twice?

For example,
Given sorted array nums = [1,1,1,2,2,3],

Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn't matter what you leave beyond the new length.

 

public class Solution {
    public int removeDuplicates(int[] nums) {
        if (nums == null) {
            return 0;
        }
        if (nums.length < 3) {
            return nums.length;
        }
        int len = nums.length;
        int p1 = 1, p2 = 2;
        while (p2 < len) {
            if (nums[p1 - 1] == nums[p1] && nums[p1] == nums[p2]) {
                while (p2 < len && nums[p2] == nums[p1]) {
                    ++p2;
                }
                if (p2 == len) {
                    break;
                }
            }
            // swap
            int tmp = nums[p1 + 1];
            nums[p1 + 1] = nums[p2];
            nums[p2] = tmp;
            ++p1;
            ++p2;
        }
        return p1 + 1;
    }
}

 

你可能感兴趣的:(Binary search)