代码随想录算法训练营第一天 | 数组part01

136 阅读3分钟

代码随想录算法训练营第一天 | 数组part01

704.二分查找

二分法思想

前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件,当看到题目描述满足如上条件的时候,可要想一想是不是可以用二分法了。

写法

说白了就是一个逻辑的理解,争取能够写出来一个顺口溜。

image.png

额....上面的思路是错的,因为区间是一直跟着的....如果是左闭右开的情况,那么在所有的区间里面都是左闭右开...并不是只在最大的区间里是。

# 左闭右闭
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 = 47
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