yaohustiAC 2020-06-11
不积跬步,无以至千里;不积小流,无以成江海。
内容主要是个人学习使用,题目分类以及部分参考资料来自于CyC的博客,非常感谢大佬,题目来源于LeetCode,非常感谢本站支持。
二分查找又称折半查找,顾名思义就是每查找比较一次,就会去掉一半的不匹配项,重复执行此步骤直到找到目标元素或者不可以在分割
实现?int sqrt(int x)?函数。
计算并返回?x?的平方根,其中?x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4 输出: 2
示例 2:
输入: 8 输出: 2 说明: 8 的平方根是 2.82842..., ? 由于返回类型是整数,小数部分将被舍去。
解题思路:
计算平方根可以采用多种方法,具体可参考LeetCode官方,
代码实现
class Solution: def mySqrt(self, x: int) -> int: if (x <= 1): # 处理0,1特殊情况 return x; left = 1 right = x // 2 # 确定区间 while left <= right: mid = left + (right-left) // 2 num = mid * mid if num > x: right = mid - 1 elif num < x: left = mid + 1 elif num == x: return mid return right
给你一个排序后的字符列表letters
,列表中只包含小写英文字母。另给出一个目标字母?target
,请你寻找在这一有序列表里比目标字母大的最小字母。
在比较时,字母是依序循环出现的。举个例子:
target = ‘z‘
并且字符列表为letters = [‘a‘, ‘b‘]
,则答案返回‘a‘
示例:
输入: letters = ["c", "f", "j"] target = "a" 输出: "c" 输入: letters = ["c", "f", "j"] target = "c" 输出: "f"
解题思路:
target
代码实现
class Solution: def nextGreatestLetter(self, letters: List[str], target: str) -> str: left = 0 right = len(letters) - 1 while left <= right: mid = left + (right - left) // 2 if letters[mid] > target: right = mid - 1 elif letters[mid] < target: left = mid + 1 else: left = mid + 1 return letters[left] if left < len(letters) else letters[0]
给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
示例 1:
输入: [1,1,2,3,3,4,4,8,8] 输出: 2
示例 2:
输入: [3,3,7,7,10,11,11] 输出: 10
注意: 您的方案应该在 O(log n)时间复杂度和 O(1)空间复杂度中运行。
解题思路:
[1,1,2,2,3,3,4,5,5]
,该数组分割后前[1,1,2,2]
,后为[3,4,5,5]
,由于都是偶数个,所以必定有一组是不含单一元素的,我们只需要比较中间元素和前一元素是否相等,不想等的则是正确一组,反之是需要下次查找[3,3,7,7,10,11,11]
,该数组分割后前[3,3,7]
,后为[10,11,11]
,由于都是奇数个,所以不能确定那一组到底是包含单一元素,我们仍然通过比较中间元素和前一元素是否相等,则相等则表示那一组是正确的,反之不正确。代码实现
class Solution: def singleNonDuplicate(self, nums: List[int]) -> int: left = 0 right = len(nums) - 1 while left <= right: mid = left + (right - left) // 2 tag = len(nums[:mid]) % 2 == 0 # 判断分割的左侧是不是偶数对 if tag: if nums[mid] == nums[mid - 1]: right = mid - 1 else: left = mid + 1 else: if nums[mid] == nums[mid - 1]: left = mid + 1 else: right = mid - 1 return nums[right]
假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用?bool isBadVersion(version)?接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例:
给定 n = 5,并且 version = 4 是第一个错误的版本。 调用 isBadVersion(3) -> false 调用 isBadVersion(5)?-> true 调用 isBadVersion(4)?-> true 所以,4 是第一个错误的版本。?
解题思路:
mid
版本是正确的,则表示错误版本处于[mid+1,right]
,不断缩减右区间mid
版本是错误的,则表示错误版本处于[left,mid]
,不断缩减左区间代码实现
class Solution: def firstBadVersion(self, n): """ :type n: int :rtype: int """ left = 1 right = n while left < right: mid = left + (right - left) // 2 if isBadVersion(mid): right = mid else: left = mid + 1 return left
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组?[0,1,2,4,5,6,7] 可能变为?[4,5,6,7,0,1,2]?)。
请找出其中最小的元素。你可以假设数组中不存在重复元素
示例 1:
输入: [3,4,5,1,2] 输出: 1
示例 2:
输入: [4,5,6,7,0,1,2] 输出: 0
解题思路:
[4, 5, 6, 7, 0, 1, 2], mid = 3, nums[mid] = 7, nums[-1] = 2
, 故 nums[mid] > nums[-1]
,说明数组旋转后较小的一部分升序序列在mid右边,更新区间:left = mid + 1
;[6, 7, 1, 2, 3, 4, 5], mid = 3, nums[mid] = 2, nums[-1] = 5
,故 nums[mid] < nums[-1]
,说明数组旋转后较小的一部分升序序列在mid左边,更新区间:right = mid - 1
。代码实现
class Solution: def findMin(self, nums: List[int]) -> int: left = 0 right = len(nums) - 1 while left <= right: mid = left + (right - left) // 2 if nums[mid] > nums[-1]: left = mid + 1 else: right = mid - 1 return nums[left]
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是?O(log n) 级别。
如果数组中不存在目标值,返回?[-1, -1]。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4]
示例?2:
输入: nums = [5,7,7,8,8,10], target = 6 输出: [-1,-1]
解题思路:
代码实现
class Solution: def searchRange(self, nums: List[int], target: int) -> List[int]: left = 0 right = len(nums) - 1 ret = [] while left <= right: mid = left + (right - left) // 2 if nums[mid] > target: right = mid - 1 elif nums[mid] < target: left = mid + 1 else: right = mid - 1 if left == len(nums): ret.append(-1) else: ret.append(left if nums[left] == target else -1) left = 0 right = len(nums) - 1 while left <= right: mid = left + (right - left) // 2 if nums[mid] > target: right = mid - 1 elif nums[mid] < target: left = mid + 1 else: left = mid + 1 if left == 0: ret.append(-1) else: ret.append(left-1 if nums[left-1] == target else -1) return ret