一、今日任务
977.有序数组的平方
209.长度最小的子数组
59.螺旋矩阵II
二、有序数组的平方
2.1 题目:977.有序数组的平方
2.2 解题过程
拿到题目第一时间想到的解法是先一边循环计算平方,再一遍循环排序。
代码如下
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
for i in range(0, len(nums)):
nums[i] = nums[i] * nums[i]
for i in range(0, len(nums)):
for j in range(1, len(nums) - i):
if nums[j] < nums[j-1]:
temp = nums[j-1]
nums[j-1] = nums[j]
nums[j] = temp
return nums
毫不意外,超时。
也看到了建议在O(n)的时间复杂度里解出来。
其实可以看做一个非有序的数组进行排序。只要找到O(n)的排序方法就行。
这是想到了归并排序。只要找到分段处就可以执行。
代码如下:
def sortedSquares1(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
NewNums = []
flag = -1
for i in range(0, len(nums)):
if nums[i] < 0:
flag = i
nums[i] = nums[i] * nums[i]
if flag == -1:
return nums
else:
n = flag
p = flag + 1
i = 0
while n >= 0 and p < len(nums):
if nums[n] < nums[p]:
NewNums.append(nums[n])
n -= 1
else:
NewNums.append(nums[p])
p += 1
i += 1
while i < len(nums) and n >= 0:
NewNums.append(nums[n])
n -= 1
i += 1
while i < len(nums) and p < len(nums):
NewNums.append(nums[p])
p += 1
i += 1
return NewNums
但是依然有不足之处,
所以,速度不够,内存耗费多。
2.3 阅读材料改进
文章中指出的双指针法,比自己思考的程度更深一些,发挥这题的特色,节省寻找分段点的时间。
同时,也给出了自己看力扣给出的内存和速度其实并不准确。
即自己是O(2n)的时间复杂度,而文章给出的是O(n)的时间复杂度。
以下是复现代码:
def sortedSquares2(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
NewNums = [None]*len(nums)
left = 0
right = len(nums)-1
i = len(nums) - 1
while left <= right:#i>=0也对
if nums[left] * nums[left] > nums[right] * nums[right]:
NewNums[i] = nums[left] * nums[left]
left += 1
else:
NewNums[i] = nums[right] * nums[right]
right -= 1
i -= 1
return NewNums
三、长度最小的子数组
3.1 题目: 209.长度最小的子数组
3.2 解题过程
注意:N个正整数,和一个正整数target。
要求:连续子数组,满足在原数组里最短的和>=target。如果不存在返回0。
首先的确是一头雾水,又回到算法题的常见模式,无敌复杂脑袋。
那就先思考暴力算法。
超时的暴力解法如下,18/20
class Solution(object):
# 暴力算法
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
MinLen = len(nums) + 1
for i in range(0, len(nums)):
sum = 0
for j in range (i, len(nums)):
sum += nums[j]
if sum >= target:
if MinLen > j-i+1:
MinLen = j-i+1
break
if MinLen == len(nums) + 1:
return 0
return MinLen
接着根据提示写出滑动窗口的方法,遇到的问题是遇到满足>=target后的更新问题。
def minSubArrayLen2(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
MinLen = len(nums) + 1
begin = 0
end = 0
sum = 0
while end < len(nums):
sum += nums[end]
if sum >= target:
if MinLen > end - begin + 1:
MinLen = end - begin + 1
# 重点
sum -= nums[begin]
begin += 1
sum -= nums[end]
end -= 1
end += 1
if MinLen == len(nums) + 1:
return 0
return MinLen
3.3 阅读材料改进
3.3.1 滑动窗口知识点
寻找连续子数组应该是非常常用的方法。
滑动窗口包括三点非常重要的地方:
- 窗口里是什么
- 起始位置在什么情况下变化
- 终止位置在什么情况下变化
在本题中,窗口里是sum,当sum>=target时起始位置前移,当sum<target 时终止位置前移。结束条件是遍历完数组。
以下是代码复现:
def minSubArrayLen3(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
MinLen = len(nums) + 1
begin = 0
end = 0
sum = 0
while end < len(nums):
sum += nums[end]
while sum >= target:
if MinLen > end - begin + 1:
MinLen = end - begin + 1
sum -= nums[begin]
begin += 1
end += 1
if MinLen == len(nums) + 1:
return 0
return MinLen
显然会比一个while,彻底解决自己得一个很大的问题。
四 、螺旋矩阵II
4.1 题目: 59.螺旋矩阵II
4.2 解题过程
首先这个题目有够让人闻风丧胆的意味在的。
同样是没有什么头绪。
按照老方法,先暴力再找有没有更好的解法。可是怎么暴力呢。
思考方向,就是为每一个数安排位置。
第一个解法,思路是顺时针嘛,顺序是右下左上,但是,忽略了惯性的原因而导致错误。
错误代码如下:
# 暴力解法:右下左上,错误解法
def generateMatrix(self, n):
"""
:type n: int
:rtype: List[List[int]]
"""
nums = [[0 for col in range(n)] for row in range(n)]
val = 1
row = 0
col = 0
while val <= n*n:
nums[row][col] = val
if col+1 < n and nums[row][col+1] == 0:
col += 1
elif row+1 < n and nums[row+1][col] == 0:
row += 1
elif col-1 >= 0 and nums[row][col-1] == 0:
col -= 1
elif row - 1 >= 0 and nums[row - 1][col] == 0:
row -= 1
val += 1
return nums
再次尝试,考虑惯性,其中当惯性不满足,只要改变一个方向就一定能走。
代码如下:
class Solution(object):
# 考虑惯性
def generateMatrix(self, n):
"""
:type n: int
:rtype: List[List[int]]
"""
nums = [[0 for col in range(n)] for row in range(n)]
val = 1
row = 0
col = 0
step = 0
row_step = [0, 1, 0, -1]
col_step = [1, 0, -1, 0]
while val <= n * n:
nums[row][col] = val
if row+row_step[step] < n and row+row_step[step] >= 0 and\
col+col_step[step] < n and col+col_step[step] >= 0 and \
nums[row+row_step[step]][col+col_step[step]] == 0:
row += row_step[step]
col += col_step[step]
else:
step = (step + 1) % 4
row += row_step[step]
col += col_step[step]
val += 1
return nums
4.3 阅读材料改进
随想录中给的是自己最开始的思路,同时通过随想录发现了自己的错误的解决方法。
可以通过圈层的计算来规避。同时一定要记住左闭右开!
以下是改进算法:
def generateMatrix2(self, n):
"""
:type n: int
:rtype: List[List[int]]
"""
nums = [[0 for col in range(n)] for row in range(n)]
val = 1
row = 0
col = 0
loop, mid = n//2, n//2
for offset in range(1, loop+1):
for i in range(col, n-offset):
nums[row][i] = val
val += 1
for i in range(row, n-offset):
nums[i][n-offset] = val
val += 1
for i in range(n-offset, col, -1):
nums[n-offset][i] = val
val += 1
for i in range(n-offset, row, -1):
nums[i][col] = val
val += 1
col += 1
row += 1
if n % 2 != 0: # n为奇数时,填充中心点
nums[mid][mid] =val
return nums
五、总结
这两天一共完成了5道题目。
第一道二分查找,复习了二分查找的两个基本方法,左闭右闭和左闭右开。
左闭右闭:
left=0,right=len(nums)-1
while(left<=right)
left = middle+1, right=middle-1
左闭右开:
left=0,right=len(nums)
while(left<right)
left = middle+1, right=middle
第二道 移除元素,学习到了快慢指针法。一个慢定位,一个快查找。
第三道 平方数组,双向指针法,和自己的归并。
第四道 最小子数组,学习到了滑动窗口,这其中最重要的还是窗口里是什么,起始位置变化条件,结束位置变化条件。其中的while真的是非常巧妙。
第五道 螺旋矩阵,顺时针加惯性。
其实还是没有领会到不变性的魅力。希望二刷能够。