代码随想录训练营第一天|Leetcode 704、34、35、27

参考来源:代码随想录网站:代码随想录


前言

 day1基本内容是二分查找(Leetcode 704)以及快慢指针删除元素(Leetcode 27)。在此基础上,Leetcode 34 和 35可以作为二分法的拓展内容,对二分法有一个更深的了解。

一、704 二分法查找元素

        在数组中查找元素, 在数据量少的情况下可以使用暴力解法,即遍历数组,判断数组中的每个值是否与目标值相等, 时间复杂度为o(n)。但是在数据量大的时候,使用二分法可以提高查找效率,时间复杂度为o(log n),其中log以2为底。

        举个例子,在1-100中随机生成一个数,我们去猜这个数是什么。我们首先要猜50,然后给出提示50比目标值大还是比目标值小,进行下一步猜测。若50大于目标值,则下一个猜测为25,若50小于目标值,则下一个猜测75.若等于目标值等于50则结束。以此类推,最终可以找到目标值,如果目标值存在于数组中。

        二分法有两种写法,一种是左闭右闭,第二种是左闭右开。

1.左闭右闭

两种方法的区别主要在两个方面

   ①左指针l指向数组第一个元素,右指针r指向列表最后一个元素。所以当只剩1个元素需要判断的时候,l = = r, 此时仍需判断所剩的一个元素是否为目标值。因此while循环条件为l<=r.

   ②当目标值大于中间值时,下一次循环时,右指针应指向中间值的前一个值,所以r = middle - 1

def search(nums, target):
    l = 0
    r = len(nums) - 1
    while l <= r:
        middle = l + (r - l)//2
        if nums[middle] < target:
            l = middle + 1
        elif nums[middle] > target:
            r = middle -1
        else:
            return middle
    return -1

2.左闭右开

  ①左闭右开时右指针r为数组最后一个元素的索引加一,因此当只剩一个元素的时候r=l+1, 所以while循环条件只需要l < r

   ②当目标值大于中间值时,下一次循环时,有效数组为中间值之前的数组, 所以中间值的上一个值为下一次循环的数组的最后一个值, 所以右指针应指向中间值,r = middle 

def search(nums, target):
    l = 0
    r = len(nums)
    while l < r:
        middle = l+(r - l)//2
        if nums[middle] < target:
            l = middle + 1
        elif nums[middle] > target:
            r = middle
        else:
            return middle
    return -1

二、27 删除元素 

       该题目给出了一个数组和要删除的目标值,本题目若采用暴力解法,则用两层for循环,一层遍历数组,一层更新数组。时间复杂度为o(n^{_{2}})。更好的方法是采用双指针法,快指针来遍历数组,慢指针更新数组。初始时,快慢指针都指向第一个元素,然后判断快指针所指的元素是否为要删除的目标值,若等于要删除的目标值target, 则快指针 + 1,若不等于target,则慢指针指向的元素赋值为快指针指向的元素。同时,快慢指针均 + 1。该算法的时间复杂度为o(n),要优于暴力解法。

代码如下

def delete(nums, val):
    slow = 0
    for fast in range(len(nums)):

        if nums[fast] != val:
            nums[slow] = nums[fast]
            slow += 1
    nums = nums[:slow]
    return slow, nums[:slow]

三、34 在排序数组中查找元素第一个元素和最后一个元素的位置

本题目为二分法的拓展题目,主要考察二分法的应用。解决本题先根据二分法定义一个Lower bound函数。该函数的参数为数组nums和目标值target。该函数的返回值则是num中,最后一个小于target的元素的下标再加1。例如:nums = [1, 2, 3, 4, 5], target = 3, 则最后一个小于3的元素是2,它的下标是1,所以返回值应该是2的下标再加一,也就是返回2。

lowerbound函数代码如下

    def lowerbound(nums, target):
        left = 0
        right = len(nums)
        while left < right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return left

有了该函数后,如果要找的目标值为target。如果lowerbound(nums, target)返回的数组下标指向的元素不是target,或者返回值等于数组的长度,则target不在数组中。其他情况下,target存在nums中, 第一个target值在nums数组中的位置就是lowerbount(nums, target)的返回值,最后一个target的位置则是lowerbound(nums, target + 1)的返回值。

整体代码如下

def searchRange( nums, target):



    def lowerbound(nums, target):
        left = 0
        right = len(nums)
        while left < right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return left

    start = lowerbound(nums, target)
    end = lowerbound(nums, target + 1) - 1

    if start == len(nums) or nums[start] != target:
        return [-1, -1]
    else:
        return [start, end]

四、35 搜索插入位置

给定一个排序好的数组nums,将target插入nums,且插入后依然是按顺序排列。本题与34题几乎相同。还是用到之前的lowerbound函数。来判断数组中最后一个小于target值的位置,然后即可在最后一个小于target值的下一个位置插入target。

代码如下

def search(nums, target):
    def insert(nums, target):
        l = 0
        r = len(nums) - 1
        while l <= r:
            middle = l + (r - l)//2
            if nums[middle] < target:
                l = middle + 1
            else:
                r = middle - 1
        return l

    last_ele = insert(nums, target)
    if last_ele == len(nums) or nums[last_ele] != target:
        nums.insert(target, last_ele)
    return last_ele

总结

要熟练掌握二分法的两种写法,同时掌握在题目34、35中出现的lowerbound函数的写法以及具体意义。它是二分法的一种变种,原理与二分法基本类似。在题目27中,要掌握关于快慢指针的用法

第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值