LeetCode 704 二分查找
题目描述:
给定一个
n
个元素有序的(升序)整型数组nums
和一个目标值target
,写一个函数搜索nums
中的target
,如果目标值存在返回下标,否则返回-1
。输入:nums = [-1,0,3,5,9,12],target = 9 输出: 4 解释: 9 出现在nums中并且下标为 4
注意点
- 有序数组
- 无重复元素
- 注意左右开闭区间,避免重复遍历或遗漏右区间元素
方法一:左闭右闭区间 [left, right]
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
#method 1
left = 0
right = len(nums) - 1
while left <= right:
# mid = (left + right) // 2
mid = left + (right-left) // 2 #难点
print(left, mid, right)
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
方法二:左闭右开区间 [left, right)
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
#method 2
left = 0
right = len(nums)
while left < right:
# mid = (left + right) // 2
mid = left + (right-left) // 2 #难点
print(left, mid, right)
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid
return -1
难点
关于mid的计算,最开始直接用的 mid = (left + right) // 2 ,可能测试用例比较少没有遇到报错,侥幸通过。后来看了别人的分析后才反应过来。(附上原解析)
- 这个问题我思考很久,
mid = (right - left) // 2
、mid = (right + left) // 2
以及mid = left + (right - left) // 2
mid = (right - left) // 2
这种写法运用在这里根本就是错误的。因为right - left 仅仅代表两者之间相差几个数的距离,再除以2只是说从左到右的一半距离,和下标就没有关系了。
mid = (right + left) // 2
这种写法会发生上溢问题。int 占用 4 字节,32 比特,数据范围为:2147483648 ~ 2147483647
[-2^31 ~ 2^31-1]
那么对于两个都接近
2147483647
的数字而言,它们相加的结果将会溢出,变成负数。所以,为了避免溢出情况的发生,我们不采用这种写法。
mid = left + (right - left) // 2
从左指针到右指针的一半距离 + 左指针的下标 才是符合题的下标位置。
LeetCode 27 移除元素
给你一个数组
nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用
O(1)
额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2] 解释:函数应该返回新的长度2, 并且nums中的前两个元素均为2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而nums = [2,2,3,3] 或nums = [2,2,0,0],也会被视作正确答案。
方法一:暴力法
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
length = len(nums)
count = 0
for i in range(length):
print(i)
if nums[i] == val:
nums[i] = 51 #原题限定num[i] <= 50
count += 1
print(nums)
print(count)
nums.sort()
return length - count
方法二:双指针法
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
slow, fast = 0, 0
length = len(nums)
for fast in range(length):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
return slow
fast::在前面遍历数组元素
slow:在后面更新数组元素
值等于target的元素不会被更新到新数组下表slow里,因此新数组前slow个元素为移除目标元素后的目标数组。
总结
- 二分法看一遍基本理解,需要注意左右区间的开闭,以及mid的计算
- 双指针法属于新学的一种,感觉这种快慢指针思想可以运用到很多地方,但是容易忘记,需要时不时看题解复习
- 第一次写博客,敬请多多指教~
代码随想录讲解原文链接: