今天是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