代码随想录算法训练营第一天 | 数组part01
704.二分查找
二分法思想
前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。
写法
说白了就是一个逻辑的理解,争取能够写出来一个顺口溜。
额....上面的思路是错的,因为区间是一直跟着的....如果是左闭右开的情况,那么在所有的区间里面都是左闭右开...并不是只在最大的区间里是。
# 左闭右闭
left,right = 0,len(nums)-1
while(left<=right):
mid = left + (right-left)//2
if(nums[mid] == target):
return mid
elif(nums[mid]<target):
left = mid + 1
else:
right = mid - 1
return mid
# 左闭右开
# 其实就是右边的一直比较不了,一直不能进行比较,所以
left,right = 0,len(nums)
while(left<right):
mid = left + (right-left)//2
if(nums[mid] == target):
return mid
elif(nums[mid]<target):
left = mid + 1
else:
right = mid
return mid
[0,1,2,3,4,5,6)
找4
left = 0 right = 7 mid = 3
left = 4 right = 7 mid = 5
left = 4 right = 5 mid = 4
找7
left = 0 right = 7 mid = 3
left = 4 right = 7 mid = 5
left = 6 right = 7 mid = 6
left = 7 right = 7 mid = 7
left 就不能等于right,因为左闭右开,所以循环条件是left < right
34. 在排序数组中查找元素的第一个和最后一个位置
第一种解法:
找到左边界,找到右边界,然后合起来。
这是最直接的解法。不过在用的时候需要注意,大部分的时候出循环的条件都是left <= right,如果我们找左边界的话,那么right最后就应该是左边界,需要找一个数来接收right,如果找右边界的话,那么left就是最后的右边界,需要找一个数来接收left。
需要注意,在最后用的时候,return [leftborder+ 1 , rightborder- 1] 因为跳出循环的条件是left > right ,所以说此时对leftborder和rightborder的赋值是边界,是开区间
# 左边界
if(nums[mid] >= target):
right = mid - 1
leftborder = right
else :
left = mid + 1
# 右边界
if(nums[mid] <= target):
left = mid + 1
rightborder = left
else :
right = mid - 1
第二种解法:
找到这个数的索引,然后左右移动看是否符合题意。
细节之处在于如何实现左右移动
while left - 1 >= 0 and nums[left - 1] == target :
left -= 1
while right + 1 < len(nums) and nums[right + 1] == target:
right += 1
27.移除元素
采用双指针法,快慢指针,快指针用来遍历列表,满指针用来更新列表。
通俗的来讲,就是你走你的,你不要的东西我给你存着,你要的东西你就拿走
slow,fast = 0,0
size = len(nums)
while fast < size :
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
977.有序数组的平方
同样采用双指针法,代码很巧妙,更能理解双指针的意思。一个指针用来存数,一个指针用来比较。
l , r , i = 0, len(nums) - 1, len(nums) - 1
res = [float('inf')] * len(nums)
while l <= r:
if nums[l] ** 2 < nums[r] ** 2:
res[i] = nums[r] ** 2
r -= 1
else :
res[i] = nums[l] ** 2
l += 1
i -= 1
这种双指针的方法还有更进一步的提升空间,那就是按照列表的先进原则进行排序,然后进行倒序
(为什么要进行倒序呢?那是因为原本的数组是升序排列的,我们不一定知道最小的是谁,但一定能够知道最大的是谁,所以按照从大往小的来进行排序,之后再进行逆序输出即可。
l , r = 0 , len(nums) - 1
new_list = []
while l <= r:
if nums[l] ** 2 < nums[r] ** 2:
new_list.append(nums[r] ** 2)
r -= 1
else :
new_list.append(nums[l] ** 2)
l += 1