今日学习的文章链接和视频链接
704. 二分查找
第一想法
题目是二分查找,题干中体现了有序数组字样。
二分查找也是折半查找。
查找规则是:搜索过程从数组中间开始,如果target等于中间数字,搜索停止;如果target大于中间数字,则在右侧继续进行二分查找;如果target小于中间数字,则在左侧继续进行二分查找;如果在这个过程中数组为空,那么查找失败。
原始的想法是比较中间的数字,变量设置的也是数组中间位置的数字。
之后的想法
根据区间的不同,分为两种方法:
1、左闭右闭[left,right]
第一版错误代码:
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)
while left <= right:
middle = (left + right) // 2
if nums[middle] > target:
right = middle - 1
elif nums[middle] < target:
left = middle + 1
elif nums[middle] == target:
return middle
return -1
报错提示:
IndexError: list index out of range
~~~~^^^^^^^^
if nums[middle] > target:
Line 7 in search (Solution.py)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ret = Solution().search(param_1, param_2)
Line 39 in _driver (Solution.py)
_driver()
Line 50 in (Solution.py)
错误原因:
这里是用的是左闭右闭的区间,也就是说数组是从0~len(nums)-1的,所以right初始化=len(nums)-1
正确代码:
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums) - 1
while left <= right:
middle = (left + right) // 2
if nums[middle] > target:
right = middle - 1
elif nums[middle] < target:
left = middle + 1
elif nums[middle] == target:
return middle
return -1
2、左闭右开[left,right)
正确代码:
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)
while left < right:
middle = (left + right)// 2
if nums[middle] > target:
right = middle
elif nums[middle] < target:
left = middle + 1
elif nums[middle] == target:
return middle
return -1
3、两种方法区别
最右侧的值在左闭右开的情况中本身就不包含。
自己实现过程中遇到的困难
从理解二分查找的规则到实现代码还是有一定距离的。
一看就会,一写就废。
虽然比较的是中间数字,但是变量应该设置的是中间数字的下标。
27. 移除元素
第一想法
题干强调原地删除并且输出最后结果就可以,把和目标值一致的数值赋值为空,最后for循环输出前面不为空的值的长度。
之后的想法
1、暴力解法
错误第一版:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
for i in range(len(nums)):
if nums[i] == val:
for j in range(i+1,len(nums)):
nums[j-1] = nums[j]
return len(nums)
输出结果为[2,2,3,3],正确结果是[2,2]
错误原因:
确实是把不等于val的有用的数值移到前面了,但是数组长度的输出并没有改变,还是原始长度。
错误第二版:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
lens = len(nums)
for i in range(0,lens):
if nums[i] == val:
for j in range(i+1,lens):
nums[j-1] = nums[j]
i = i - 1
lens = lens - 1
return lens
输出结果为[2],正确结果是[2,2]
错误原因:
for range 遍历中的 i 是循环开始时就确定了的,在循环体中对其修改是无效的
正确版本:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
i,size = 0,len(nums)
while i < size:
if nums[i] == val:
for j in range(i+1,size):
nums[j-1] = nums[j]
size = size - 1
i = i - 1
i = i + 1
return size
2、双指针法
错误第一版
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
fast = 0
slow = 0
for i in range(len(nums)):
if nums[i] != val:
nums[slow] = nums[fast]
slow += 1
return slow
输出结果:输出[3,3]预期结果[2,2]
错误原因:
快慢指针中快的是一直向下找不等于val的元素,慢的是等遇到val就停止,然后fast将后续的元素覆盖到前面。所以一直向下走的不是i是fast。
正确版:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
fast = 0
slow = 0
for fast in range(len(nums)):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
return slow
自己实现过程中遇到的困难
全是困难呜呜呜呜
今日收获,记录一下自己的学习时长
1、二分查找不仅要满足有序,还要满足没有重复元素,因为一旦出现重复元素,在本题中元素的下标就不唯一了。
2、不要使用额外的数组空间,意思是必须仅使用 O(1) 额外空间并原地修改输入数组。
3、其实快慢指针还不是很了解,为什么这个题就可以用快慢指针,遇到其他的题想不起来这种做法。。。。