5月7日 - 二分法
Posted li-ling
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5月7日 - 二分法相关的知识,希望对你有一定的参考价值。
二分法 Binary Search Given a sorted integer array - nums, and an integer - target, find the any/first/last position of target in nums. Return -1 if target does not exist.
O(1)极少
O(logn) 二分法
O(n) 大部分
O(nlogn) 排序
O(n^2) 数组 动态规划
是否使用递归 递归的函数深度
二分法模板
1、start + 1 < end
2、start + (end - start) / 2
3、A[mid]==, <, >
4、A[start] A[end] target
如果写成start < end,除以2一般向左靠,可能产生死循环。 中间的循环不断缩小,直到你用眼睛看,用手数就能找到结果。
1、经典二分查找问题
在一个排序数组中找一个数,返回该数出现的任意位置,如果不存在,返回-1
public class Solution { /* * @param nums: An integer array sorted in ascending order * @param target: An integer * @return: An integer */ public int findPosition(int[] nums, int target) { // write your code here if (nums == null || nums.length == 0) { return -1; } // 非常重要! int start = 0, end = nums.length - 1; while (start + 1 < end) {
int mid = start + (end - start) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] < target) { start = mid; } else if (nums[mid] > target) { end = mid; } } if (nums[start] == target) return start; if (nums[end] == target) return end; return -1; } }
2、给定一个排序的整数数组(升序)和一个要查找的整数target
,用O(logn)
的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1
。
第一个错误代码的版本(类似第一个满足条件的下标) 要考虑if...else...的条件判断,能解决问题就行,无需多次调用判断函数 SVNRepo.isBadVersion(),以免超时。
/** * public class SVNRepo { * public static boolean isBadVersion(int k); * } * you can use SVNRepo.isBadVersion(k) to judge whether * the kth code version is bad or not. */ public class Solution { /* * @param n: An integer * @return: An integer which is the first bad version. */ public int findFirstBadVersion(int n) { // write your code here int start = 1, end = n; while (start + 1 < end) { int mid = start + (end - start) / 2; if (SVNRepo.isBadVersion(mid)) { end = mid; } else { start = mid; } } if (SVNRepo.isBadVersion(start)) { return start; } return end; } }
3、
假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2)。
你需要找到其中最小的元素。
你可以假设数组中不存在重复的元素。
Ans:很自然想到要用O(logn)解法 -> 二分,即first position <= last number
非有序怎么解决?若last < mid,最小在右;若last > mid,最小在左或本位;
特殊情况,nums[start] < nums[end],直接返回首位,减少计算时间
public class Solution { /** * @param nums: a rotated sorted array * @return: the minimum number in the array */ public int findMin(int[] nums) { // write your code here int start = 0, end = nums.length - 1; if (nums[start] < nums[end]) { return nums[start]; } while (start + 1 < end) { int mid = start + (end - start) / 2; if (nums[mid] < nums[end]) { end = mid; } else { start = mid; } } if (nums[start] < nums[end]) { return nums[start]; } else { return nums[end]; } } }
4、
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. 一定要注意数组判断是否为null或者数组长度为0。
public class Solution { /** * @param matrix: matrix, a list of lists of integers * @param target: An integer * @return: a boolean, indicate whether matrix contains target */ public boolean searchMatrix(int[][] matrix, int target) { // write your code here 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 start = 0, end = m * n - 1; while (start + 1 < end) { int mid = start + (end - start) / 2; int temp = matrix[mid / n][mid % n]; if (temp == target) { return true; } else if (temp < target) { start = mid; } else { end = mid; } } if (matrix[start / n][start % n] == target || matrix[end / n][end % n] == target) { return true; } else { return false; } } }
5、
Given a sorted array of n integers, find the starting and ending position of a given target value.
If the target is not found in the array, return [-1, -1]
. 注意return new int[]{-1, -1};
public class Solution { /** * @param A: an integer sorted array * @param target: an integer to be inserted * @return: a list of length 2, [index1, index2] */ public int[] searchRange(int[] A, int target) { // write your code here if (A == null || A.length == 0) { return new int[]{-1, -1}; } int start = 0, end = A.length - 1; int firstIndex = -1, endIndex = -1; while (start + 1 < end) { int mid = start + (end - start) / 2; if (A[mid] == target) { end = mid; } else if (A[mid] > target) { end = mid; } else { start = mid; } } if (A[start] == target) { firstIndex = start; } else if (A[end] == target) { firstIndex = end; } else { return new int[]{-1, -1}; } endIndex = firstIndex; while (endIndex <= A.length - 1) { if (A[endIndex] != target) { break; } endIndex++; } return new int[]{firstIndex, endIndex-1}; } }
以上是关于5月7日 - 二分法的主要内容,如果未能解决你的问题,请参考以下文章