二分查找也稱折半查找(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