给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1:
1 2 输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2:
1 2 输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3:
1 2 输入: nums = [1,3,5,6], target = 7 输出: 4
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 为 无重复元素 的 升序 排列数组
-104 <= target <= 104
思路 不多说,都会
代码 1 2 3 4 5 6 7 8 9 10 11 12 class Solution : def searchInsert (self, nums: List [int ], target: int ) -> int : left, right = 0 , len (nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] == target: return mid elif nums[mid] < target: left = mid + 1 else : right = mid - 1 return left
给你一个满足下述两条属性的 m x n 整数矩阵:
每行中的整数从左到右按非严格递增顺序排列。
每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。
示例 1:
1 2 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]] , target = 3 输出:true
示例 2:
1 2 输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]] , target = 13 输出:false
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 100
-104 <= matrix[i][j], target <= 104
思路 其实和前一题一样,但有几个需要注意的点
由于是二维数组,我们的mid是线性索引,所以需要一个额外变量表示mid位置的元素
三个条件判断需要用到的是额外变量而不是mid索引指向
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution : def searchMatrix (self, matrix: List [List [int ]], target: int ) -> bool : if not matrix or not matrix[0 ]: return False rows, cols = len (matrix), len (matrix[0 ]) left, right = 0 , rows * cols - 1 while left <= right: mid = (left + right) // 2 mid_value = matrix[mid // cols][mid % cols] if mid_value == target: return True elif mid_value < target: left = mid + 1 else : right = mid - 1 return False
时间复杂度 时间复杂度O(log(n * m)),空间复杂度O(1),执行时间44ms,消耗内存16.8MB
162 寻找峰值 Medium 峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞ 。
你必须实现时间复杂度为 O(log n) 的算法来解决此问题。
示例 1:
1 2 3 输入:nums = [1,2,3,1 ] 输出:2 解释:3 是峰值元素,你的函数应该返回其索引 2 。
示例 2:
1 2 3 4 输入:nums = [1,2,1,3,5,6,4] 输出:1 或 5 解释:你的函数可以返回索引 1 ,其峰值元素为 2 ; 或者返回索引 5 , 其峰值元素为 6 。
提示:
1 <= nums.length <= 1000
-231 <= nums[i] <= 231 - 1
对于所有有效的 i 都有 nums[i] != nums[i + 1]
思路 逻辑上都差不多,需要注意的是严格大于两边我们只取大于小于右边作为主要条件
代码 1 2 3 4 5 6 7 8 9 10 class Solution : def findPeakElement (self, nums: List [int ] ) -> int : left, right = 0 , len (nums) - 1 while left < right: mid = (left + right) // 2 if nums[mid] > nums[mid + 1 ]: right = mid else : left = mid + 1 return left
时间复杂度 时间复杂度O(log n),空间复杂度O(1),执行时间33ms,消耗内存16.6MB
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
示例 1:
1 2 输入:nums = [4,5,6,7,0,1,2] , target = 0 输出:4
示例 2:
1 2 输入:nums = [4,5,6,7,0,1,2] , target = 3 输出:-1
示例 3:
1 2 输入:nums = [1 ], target = 0 输出:-1
提示:
1 <= nums.length <= 5000
-104 <= nums[i] <= 104
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-104 <= target <= 104
思路 这里唯一需要注意的就是我们需要去判断有序区间,别的都是正常二分
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution : def search (self, nums: List [int ], target: int ) -> int : left, right = 0 , len (nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] == target: return mid if nums[left] <= nums[mid]: if nums[left] <= target <= nums[mid]: right = mid - 1 else : left = mid + 1 else : if nums[mid] <= target <= nums[right]: left = mid + 1 else : right = mid - 1 return -1
时间复杂度 时间复杂度O(log n),空间复杂度O(1),执行时间45ms,消耗内存16.7MB
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例 1:
1 2 输入:nums = , target = 8 输出:
示例 2:
1 2 输入:nums = , target = 6 输出:
示例 3:
1 2 输入:nums = , target = 0 输出:
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109
思路 需要两个额外变量存储索引,需要边界条件确定不存在的情况
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution : def searchRange (self, nums: List [int ], target: int ) -> List [int ]: left, right = 0 , len (nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] < target: left = mid + 1 else : right = mid - 1 first = left if first == len (nums) or nums[first] != target: return [-1 , -1 ] left, right = 0 , len (nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] > target: right = mid - 1 else : left = mid + 1 last = right return [first, last]
时间复杂度 时间复杂度O(log n),空间复杂度O(1),执行时间43ms,消耗内存17.7MB
1 2 3 输入:nums = [4,5,6,7,0,1,2] 输出:0 解释:原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。
示例 3:
1 2 3 输入:nums = [11,13,15,17] 输出:11 解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。
提示:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 中的所有整数 互不相同
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转
思路 没啥差别和找峰值那个差不多,一个找索引一个找值
代码 1 2 3 4 5 6 7 8 9 10 class Solution : def findMin (self, nums: List [int ] ) -> int : left, right = 0 , len (nums) - 1 while left < right: mid = (left + right) // 2 if nums[mid] > nums[right]: left = mid + 1 else : right = mid return nums[left]
时间复杂度 时间复杂度O(log n),空间复杂度O(1),执行时间36ms,消耗内存16.7MB
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
1 2 3 输入:nums1 = , nums2 = 输出:2.00000 解释:合并数组 = ,中位数 2
示例 2:
1 2 3 输入:nums1 = [1 ,2 ], nums2 = [3 ,4 ] 输出:2.50000 解释:合并数组 = [1 ,2 ,3 ,4 ] ,中位数 / 2 = 2.5
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
思路 两个数组和成一个数组然后去处理,排序后直接分奇偶
代码 1 2 3 4 5 6 7 8 9 class Solution : def findMedianSortedArrays (self, nums1: List [int ], nums2: List [int ] ) -> float : nums = nums1 + nums2 nums.sort() length = len (nums) if length % 2 == 0 : return (nums[length // 2 - 1 ] + nums[length // 2 ]) / 2 else : return nums[length // 2 ]
时间复杂度 时间复杂度O((n + m) log(n + m)),空间复杂度O(n + m),执行时间41ms,消耗内存16.6MB