从零开始刷Leetcode——数组(27.35.53)


今天是27.35.53题。27和昨天的26题思想差不多,35比较简单,53确实想了一段时间。

27.移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

1.反向遍历

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        length = len(nums)
        for i in range(length-1, -1, -1):
            if nums[i] == val:
                nums.pop(i)
            else:
                continue
        return len(nums)

和上一题思路一模一样,不祥述,48ms

2.单指针

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        length = len(nums)
        j=0
        for i in range(length):
            if nums[i] != val:
                nums[j]=nums[i]
                j = j+1
        nums = nums[:j]
        return len(nums)

60ms

3.没什么意义的解法

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        try:
            while True:
                nums.remove(val)
        except:
            return len(nums)

参考别人的,代码没什么太大意义,就是速度快点,36ms

35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

1.逐个比较

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        length = len(nums)
        for i in range(length):
            if nums[i] >= target:
                return i
        return length       

不说了,很简单,48ms

2.二分查找

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        length = len(nums)
        l=0
        r=length-1
        while(l<=r):
            mid = (l+r)//2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                l = mid+1
            else:
                r = mid -1
        return l

这个应该是标准解法,44ms,还能更快,不知道怎么弄了

53.最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

1.暴力计算

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        length = len(nums)
        max_ = nums[0]
        sum_ = nums[0]
        for i in range(1, length):
        	# 当当前序列加上此时的元素的值大于当前元素的值,说明最大序列和可能出现在后续序列中,记录此时的最大值
            if sum_ + nums[i] > nums[i]:
                max_ = max(max_, sum_+nums[i])
                sum_ = sum_ + nums[i]
            #当当前和小于此时加上的元素时,当前最长序列到此为止。以该元素为起点继续找最大子序列,并记录此时的最大值   
            else:
                max_ = max(max_, nums[i])
                sum_ = nums[i]
        return max_

基本思路就是遍历一遍,用两个变量,一个记录最大的和,一个记录当前的和,52ms

2.分治算法

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        #递归终止条件
        if n == 1:
            return nums[0]
        else:
            #递归计算左半边最大子序和
            max_left = self.maxSubArray(nums[0:len(nums) // 2])
            #递归计算右半边最大子序和
            max_right = self.maxSubArray(nums[len(nums) // 2:len(nums)])
        
        #计算中间的最大子序和,从右到左计算左边的最大子序和,从左到右计算右边的最大子序和,再相加
        max_l = nums[len(nums) // 2 - 1]
        tmp = 0
        for i in range(len(nums) // 2 - 1, -1, -1):
            tmp += nums[i]
            max_l = max(tmp, max_l)
        max_r = nums[len(nums) // 2]
        tmp = 0
        for i in range(len(nums) // 2, len(nums)):
            tmp += nums[i]
            max_r = max(tmp, max_r)
        #返回三个中的最大值
        return max(max_right,max_left,max_l+max_r)

扒了一个大佬的代码,大概思想就是就是它的最大子序和要么在左半边,要么在右半边,要么是穿过中间,对于左右边的序列,情况也是一样,因此可以用递归处理。中间部分的则可以直接计算出来。速度虽然慢,180ms,但是思想可以借鉴一下

3.动态规划

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        dp = nums[:]  # 初始化dp数组,dp[i]存储以nums[i]为结尾的子数组的和的最大值
        res = dp[0]
        for i in range(1, len(nums)):
            dp[i] = max(dp[i], dp[i] + dp[i - 1])  # 更新dp[i]
            res = max(res, dp[i]) # 更新全局最大值
        return res

动态规划不是很懂,先放在这,学完再补充。讲解原话是dp[i] 存储的不是从 0 到 i 这个范围内所得到的最大的连续子数组的和,而是以 nums[i] 为结尾的子数组所能达到的最大的和。速度也是52ms

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值