二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。可是,折半查找要求线性表必须采用顺序存储结构,并且表中元素按关键字有序排列。二分查找法的时间复杂度是对数级别的,O(log2n)java
public int binarySearch(int [] array, double key) { int l = 0; int r = array.length - 1; while (l <= r) { int m = (l + r)/ 2; if (key == array[m]) return m; else if (key < array[m]) r = m - 1; else l = m + 1; } return l;
}
若是key在array中,返回的是key在array中的位置,若是不在array中,返回的是key应该插入的位置也就是第一个大于key的位置。这里和java.util.Arrays类返回值-(low + 1)不太同样,我的以为我这种写法作某些算法题更方便。算法
实现 int sqrt(int x)
函数。计算并返回 x 的平方根。x 保证是一个非负整数。数组
分析:函数
这道题有两种解法,二分法和拟牛顿法spa
二分法 .net
class Solution(object): def mySqrt(self, x): """ :type x: int :rtype: int """ l = 0 r = x // 2 + 1 while l <= r: m = (l + r) // 2 if m ** 2 <= x and (m + 1) ** 2 > x: return m elif m ** 2 > x: r = m - 1 else: l = m + 1
牛顿法code
class Solution: def mySqrt(self, x): """ :type x: int :rtype: int """ r = x while r*r > x: r = (r + x//r) // 2 return r
假设按照升序排序的数组在预先未知的某个关键点上旋转。xml
(即 0 1 2 4 5 6 7
将变成 4 5 6 7 0 1 2
)。blog
给你一个目标值来搜索,若是数组中存在这个数则返回它的索引,不然返回 -1。排序
你能够假设数组中不存在重复。
分析:
class Solution(object): def search(self, nums, target): """ :type nums: List[int] :type target: int :rtype: int """ l = 0 r = len(nums) - 1 while l <= r: m = (l + r) // 2 if nums[m] == target: return m if nums[m] < nums[r]: if target > nums[m] and target <= nums[r]: l = m + 1 else: r = m - 1 else: if target < nums[m] and target >= nums[l]: r = m - 1 else: l = m + 1 return -1
follow up:
若是数组元素容许重复,怎么办?
这会影响到程序的时间复杂度吗?会有怎样的影响,为何?
分析:
和Search in Rotated Sorted Array惟一的区别是这道题目中元素会有重复的状况出现。不过正是由于这个条件的出现,出现了比较复杂的case,甚至影响到了算法的时间复杂度。原来咱们是依靠中间和边缘元素的大小关系,来判断哪一半是不受rotate影响,仍然有序的。而如今由于重复的出现,若是咱们遇到中间和边缘相等的状况,咱们就丢失了哪边有序的信息,由于哪边都有多是有序的结果。假设原数组是{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)。代码以下:
class Solution: def search(self, nums, target): """ :type nums: List[int] :type target: int :rtype: int """ if not nums: return False l = 0 r = len(nums) - 1 while l <= r: m = (l + r) // 2 if nums[m] == target: return True if nums[m] < nums[r]: if target > nums[m] and target <= nums[r]: l = m + 1 else: r = m - 1 elif nums[m] > nums[r]: if target < nums[m] and target >= nums[l]: r = m -1 else: l = m + 1 else: r -= 1 return False
假设一个按照升序排列的有序数组从某未知的位置旋转。
(好比 0 1 2 4 5 6 7
可能变成 4 5 6 7 0 1 2
)。
找到其中最小的元素。
你能够假设数组中不存在重复的元素。
分析:
二分法O(log2n):
若是num[m] < num[r],说明pivot也就是最小的元素在m左边,极端状况有可能num[m]就是pivot,因此r = m 而不是 r= m -1,若是num[m] > num[r],则pivot在m的右边,因此l = m + 1
class Solution(object): def findMin(self, nums): """ :type nums: List[int] :rtype: int """ l = 0 r = len(nums) - 1 while l < r: m = (l + r) // 2 if nums[m] < nums[r]: r = m else: l = m + 1 return nums[l]
线性扫描O(n):
class Solution(object): def findMin(self, nums): """ :type nums: List[int] :rtype: int """ for i in range(len(nums) - 1): if nums[i] > nums[i + 1]: return nums[i + 1] return nums[0]
follow up:
数组中存在重复元素,处理方法与上一道题Search in Rotated Sorted Array同样,对边缘移动一步,直到边缘和中间不在相等或者相遇,这就致使了会有不能切去一半的可能。因此最坏状况(好比所有都是一个元素,或者只有一个元素不一样于其余元素,而他就在最后一个)就会出现每次移动一步,总共是n步,算法的时间复杂度变成O(n)
class Solution(object): def findMin(self, nums): """ :type nums: List[int] :rtype: int """ l = 0 r = len(nums) - 1 while l < r: m = (l + r) // 2 if nums[m] < nums[r]: r = m elif nums[m] > nums[r]: l = m + 1 else: r -= 1 return nums[l]
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组,其中 num[i] ≠ num[i+1]
,找到峰值元素并返回其索引。
数组可能包含多个峰值,在这种状况下,返回到任何一个峰值所在位置均可以。
你能够想象获得 num[-1] = num[n] = -∞
。
例如,在数组 [1, 2, 3, 1]
中 3 是峰值元素您的函数应该返回索引号2。
你的解决方案应该是对数复杂度的。
分析:
这道题与Find Minimum in Rotated Sorted Array很像,依然能够用二分法或者线性扫描两种方法解决。
二分法O(log2n):
若是nums[m] > nums[m+1],则说明m的左侧确定存在峰值,由于若是nums[m-1] < nums[m],则说明m是峰值元素,若是说nums[m -1] > nums[m],则m -1的左侧还存在峰值,若是一直到m = 0的话,那0这个位置的元素就是峰值。
class Solution(object): def findPeakElement(self, nums): """ :type nums: List[int] :rtype: int """ l = 0 r = len(nums) - 1 while l < r: m = (l + r) // 2 if nums[m] < nums[m + 1]: l = m + 1 else: r = m return l
线性扫描O(n):
若是当前元素m比前一元素m-1大的话,则继续向后搜索,若是小的话,说明前一元素m-1即为峰值,由于m-1以前的都比m-1小。
class Solution(object): def findPeakElement(self, nums): """ :type nums: List[int] :rtype: int """ for i in range(1,len(nums)): if nums[i] < nums[i - 1]: return i - 1 return len(nums) - 1
http://blog.csdn.net/linhuanmars/article/details/20588511