代码随想录算法训练营第一天|704. 二分查找 27. 移除元素
704. 二分查找
什么是二分法
文档讲解:(二分查找法是什么)
视频讲解:(卡哥 手把手手撕教学)
二分法原理
二分法(折半查找)是一种在有序数组中查找一个数组元素的方法。
目的是为了获取查找元素的下标
将目标元素一直与查找范围的中间值做比较,将比较以后的元素分为两部分:
- 若目标元素大于中间值则删除包括中间值的左半部分,保留目标元素的右半部分。得到以后再使用二分法查找,直到查找的目标元素与中间值相等。
- 小于的情况同理,删右半部分,保留左半部分。再使用二分法查找。
奇数情况
中间数字下标的计算方法
下标
=
查找范围的开始下标
+
查找范围的结束下标
2
下标=\frac{查找范围的开始下标+查找范围的结束下标}{2}
下标=2查找范围的开始下标+查找范围的结束下标
偶数情况
中间数字下标的计算方法
下标
=
向下取整
(
查找范围的开始下标
+
查找范围的结束下标
2
)
下标=向下取整\left( \frac{查找范围的开始下标+查找范围的结束下标}{2}\right)
下标=向下取整(2查找范围的开始下标+查找范围的结束下标)
704. 自己手撕版本
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
start,end = 0,len(nums)-1# 1.定义数组开始和结束索引
mid_index = int((start + end)/2) # 2.获取Target索引 向下取整
for index in range(start,end+1) :
if (target == nums[mid_index]):
return mid_index
elif target < nums[mid_index]:
end = mid_index-1
mid_index = int((start+end)/2)
continue
else:
start = mid_index+1
mid_index = int((start + end) / 2)
continue
return -1
思路:
- 根据原理,比较Target与中间数组元素的大小,从而分成两部分
- 不管大于或者小于的情况,新的范围不包含旧的mid_index.
- 二分法只需要不断的压缩范围,确定好范围,让目标元素与中间元素相比较即可。
- 使用 range 函数 来确定 搜索的范围
- 使用int 函数做到向下取整
学习卡哥课程
易错点:
-
whie循环里面的循环条件 分为两种 1. 左闭右闭 2.左闭右开
-
在进行比较以后,mid_index的更新问题
核心 : 不管是左闭右必还是左闭右开,都不能取到Middle值。
1.左闭右闭 [ ]
-
numsize = 数组长度,是最后一个元素的索引值
-
即循环变量的区间为左闭右闭,搜索范围的开始和结束都能取的到。
-
left<= right , 在【left,right】 为合法区间吗? —>数组中只有一个元素,left == right 【1,1】
-
既然搜索范围的左边界和右边界都可以取到,在进行比较划分的时候会出现mid_index一定不能包含进去,因此一定是在此情况一定是mid_index -+ 1 .
-
对于mid_index求法 start +(end- start)//2
#左闭右闭
start,end = 0,len(nums)-1# 1.定义数组开始和结束索引
while(start <= end) :
mid_index = start +(end- start)//2
if target < nums[mid_index]:
end = mid_index-1
elif target > nums[mid_index]:
start = mid_index + 1
else:
return mid_index
return -1
2.左闭右开 [, )
- 此时right = numsize
- 左闭右开 因 target小于 Middle值的时候 会更新右边界,此时因为为left<right 取不到。mid_index值不变。
#左闭右闭
start,end = 0,len(nums)# 1.定义数组开始和结束索引
while(start < end) :
mid_index = start +(end- start)//2
if target < nums[mid_index]:
end = mid_index
elif target > nums[mid_index]:
start = mid_index + 1
else:
return mid_index
return -1
27. 移除元素
学习视频:卡哥手把手教学移除元素
27. 自己手撕版本
i, l = 0, len(nums)
while i < l:
if nums[i] == val:
for j in range(i+1, l):
nums[j - 1] = nums[j]
l -= 1
i -= 1
i += 1
return l
思路:
- 纯暴力,遍历数组,寻找对应元素
- 在找到以后对后面的元素前移。数组的上边界和下边界都要变。
学习卡哥课程
如果库函数是解决问题当中的一小部分可以使用库函数
双指针思路
- 一个快指针一个慢指针,快指针寻找 新数组(删除了指定元素以后的数组)中的元素(遍历的意思),慢指针指向新数组的下标。
- 快指针指向的元素不等于 目标值的时候 即 快指针所指元素不是新数组中所需元素的时候进行赋值。
fast = 0 # 快指针
slow = 0 # 慢指针
size = len(nums)
while fast < size: # 不加等于是因为,a = size 时,nums[a] 会越界
# slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow