题目描述:给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1。
什么是二分法
直接问下ai吧,给出如下答案:
二分法,也称为二分查找或折半查找,是一种在有序数组中查找特定元素的搜索算法。这种算法的工作原理是不断地将数组的中间元素与目标值进行比较,并根据比较结果决定继续在数组的左半部分或右半部分进行查找。
以下是二分法的基本步骤:
- 初始化:确定数组的左右边界,通常是数组的第一个和最后一个元素的索引。
- 查找中间元素:计算左右边界的中点,即
(左边界 + 右边界) / 2
。 - 比较:将中间元素与目标值进行比较。
- 如果中间元素等于目标值,则查找成功,返回中间元素的索引。
- 如果中间元素大于目标值,则目标值必定位于左半部分,更新右边界为中间元素的索引减一。
- 如果中间元素小于目标值,则目标值必定位于右半部分,更新左边界为中间元素的索引加一。
- 重复:重复步骤2和3,直到找到目标值或左边界大于右边界(表示数组中不存在目标值)。
二分法的关键优势在于其效率,特别是在处理大型数据集时。每次迭代都将搜索空间减半,因此其时间复杂度为O(log n),其中n是数组的大小。这使得二分法比线性搜索(时间复杂度为O(n))在大型有序数组中查找元素时快得多。
挺靠谱的给个赞!
解题思路
既然是二分查找,必然就不会用暴力解法了,况且也会提示超时过不了。二分的精髓就是通过左右边界的不断缩小来定位。难点在于边界的确定,但只要是能够遍历所有下标,就是可行的。可以看出ai给出的解法是属于左闭右闭的思路。废话不多说直接上代码
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums)-1
while left<=right:
mid = (left+right)//2 # 向下取整
if nums[mid]<target:
left = mid+1 #左闭右闭思想
elif nums[mid]>target:
right = mid-1
else:
return mid
return -1
点击提交,good,通过了,秉着严谨的治学态度 看看是否还有优化的地方。果然mid变量还可以优化(left+right)//2 可能会造成溢出现象,所以优化成mid = left + (right - left) // 2,这下完美了。至于另一种左闭又开的思路,就大同小异了,区分在于while条件以及mid变量的更新。
给你一个数组 nums
和一个值 val
,你需要 原地 移除所有数值等于 val
的元素。元素的顺序可能发生改变。然后返回 nums
中与 val
不同的元素的数量。
假设 nums
中不等于 val
的元素数量为 k
,要通过此题,您需要执行以下操作:
- 更改
nums
数组,使nums
的前k
个元素包含不等于val
的元素。nums
的其余元素和nums
的大小并不重要。 - 返回
k
。
虽然此题可以两层for循环,暴力解也能过。但我们还是上点难度吧,这样可以学到新知识,关键字:双指针
什么是双指针,问AI
双指针算法,也称为双指针技巧或滑动窗口,是一种常用的算法技巧,主要用于解决数组或链表相关的问题。这种算法使用两个指针遍历数据结构,以解决各种问题,如查找、排序和合并等。双指针算法的关键在于如何有效地移动指针以达到问题的解决方案。
双指针算法通常分为两种类型:
-
相向双指针:两个指针从不同方向向中间移动。这种类型常用于解决数组或链表中的问题,如反转数组或链表、判断回文等。
-
同向双指针:两个指针从同一方向开始,但可能以不同的速度移动。这种类型常用于解决数组或链表中的查找问题,如查找和为特定值的元素对、查找数组中的最长子序列等。
以下是双指针算法的一个简单示例,用于查找数组中两个数的和等于给定目标值的元素对:
def two_sum(nums, target):
left, right = 0, len(nums) - 1
while left < right:
current_sum = nums[left] + nums[right]
if current_sum == target:
return [nums[left], nums[right]]
elif current_sum < target:
left += 1
else:
right -= 1
return None
在这个例子中,left
和 right
是两个指针,分别从数组的两端开始。通过比较当前两指针所指元素的和与目标值,可以决定如何移动指针。如果和小于目标值,则移动左指针向右;如果和大于目标值,则移动右指针向左。
双指针算法的优势在于其高效性,通常可以在O(n)的时间复杂度内解决问题,其中n是数组或链表的长度。这种算法特别适用于处理连续数据结构的问题,通过有效地利用指针的移动,可以避免不必要的遍历和计算。
嗯,这个解释我给满分
此题解题思路
应该用同向双指针的思路,双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。定义一个快指针寻找新数组的元素 ,新数组就是不含有目标元素的数组,再定义一个慢指针指向更新 新数组下标的位置。直接上代码
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
slow = 0
fast = 0
n = len(nums)
while fast < n:
if nums[fast] != val:
nums[slow] = nums[fast] # 修改新组数下标对应的值
slow += 1
fast += 1
return slow # 返回的就是新数组的个数
该算法的
- 时间复杂度:O(n)
- 空间复杂度:O(1)
第一天就收获满满,以前没搞懂的左闭右闭彻底清楚了,又掌握的新的知识点 双指针