文章目录
人生没那么多观众的呢?为什么昨天晚上两点钟写的博客早上起来居然几百个人看过了。。。。
977.有序数组的平方
思路
时间复杂度复杂度取决于排序,快排是O(nlogn)这里介绍双指针O(n)
分析:新数组是递增的,原来是从负数开始的递增的
快排暴力冒泡等排序方法以后补充
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
return arr
def quick_sort(arr):
if len(arr)<=1:
return arr
else:
middle = len(arr)//2
left = [x for x in arr if x<arr[middle]]
middle_ele = [arr[middle]]
right = [x for x in arr if x>arr[middle]]
return quick_sort(left)+middle_ele+quick_sort(right)
双指针排序
因为题目中从负数开始的,所以这个排序有点特殊;
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间,中间是最小值。
方法:双指针法,i指向起始位置,j指向终止位置。
定义一个新数组result,和A数组一样的大小,让k一开始指向result数组终止位置,从后往前放。【因为i和j起始的位置是最大值,而新数组要求排序为从小到大,所以是从后往前放】
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
n = len(nums)
i, j, k= 0, n-1, n-1 #分别标注原来数组的开头和结尾
nums_new = [0] * n
while i <= j:
if nums[i]**2 < nums[j]**2:
nums_new[k] = nums[j]*nums[j]
j -= 1
else: #包括了等于的情况
nums_new[k] = nums[i]*nums[i]
i += 1
k -= 1
return nums_new
209.长度最小的子数组
方法一、滑动窗口法
【非常巧妙🥰】
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
✨for循环中的应该是窗口的终止位置,也就是说我们这个终止位置遍历一次到最后就结束了。
这样就可以保证时间复杂度为O(n);这里可以看一下讲解文章里面的动图,简单易懂。
🎉我的理解:寻找每个终止位置j对应的最小窗口,最后取这些最小窗口里面的最小值 先j后i,依次滑动
具体:固定i,j先滑动,找到满足S的j之后,再向后滑动i,找到满足S、在固定j的情况下最小的j-1;再固定i,滑动j,重复操作
更具体:起始位置为i(初始为0),终止位置开始从头滑动到窗口里面的和为S,接着缩小窗口(即,移动i到最短的满足S条件的窗口)找到当前j中最大的i;再固定i,继续滑动j,重复操作;
- 窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。再去移动
- 窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。
给的都是python3的代码,所以我写了python的
记录自己写代码注意点
- range是不包括最后一个的,如果要遍历到最后,range(len(list)),不要减一啊啊啊
- cur_len = j - i + 1和len_min = cur_len if cur_len < len_min else这两行代码可以 len_minmin_len = min(min_len, right - left + 1)
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
i,n = 0, len(nums)
len_min = n+1
sum_ = 0
for j in range(n): #range是不包括最后一个的,这里还是错
sum_ += nums[j]
while sum_ >= target:#注意这里要是while而不是if,因为i往后可能会滑动不止一次
sum_ -= nums[i]
# cur_len = j - i + 1
# len_min = cur_len if cur_len < len_min else len_min
len_min = min(j-i+1,len_m)
i += 1
return len_min if len_min < n +1 else 0
方法二 暴力求解
标准答案的优雅的代码:
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
l = len(nums)
min_len = float('inf')
for i in range(l):
cur_sum = 0
for j in range(i, l):
cur_sum += nums[j]
if cur_sum >= s:
min_len = min(min_len, j - i + 1)
break
return min_len if min_len != float('inf') else 0
不知道为什么自己写就一堆bug
"""
自己暴力求解,双层遍历,结果最后超出时间。各种debug==
"""
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
start, stop = 0, len(nums) - 1
len_min = len(nums) + 1
while start < stop:
sum_ = nums[start]
if sum_ >=target:
len_cur = 1 #设置为第一个的特殊情况
len_min = len_cur if len_cur < len_min else len_min
return 1
for i in range(start + 1, stop+1):
sum_ += nums[i]
if sum_ >= target:
len_cur = i - start +1
len_min = len_cur if len_cur < len_min else len_min
break
start += 1
if nums[-1] == target:#补充为最后一个的特殊情况
return 1
return len_min if len_min < len(nums)+1 else 0
59.螺旋矩阵
这道题目可以说在面试中出现频率较高的题目**,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力**。
思路
气死我了,昨天写的思路没有保存啊啊啊啊啊狗屎
总体理解:一圈一圈地写,先写第一圈写完再写第二圈里面,不要跟着图示绕;奇数圈额外判别一下
要坚持循环不变量原则:例如下面这个图就是坚持左闭右开原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
由外向内一圈一圈这么画下去。
标准代码一
矩阵的x和y用startx, starty, offset来表征,而不是像我,i和j会被上一条边影响
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
nums = [[0] * n for _ in range(n)]
startx, starty = 0, 0 # 起始点
loop, mid = n // 2, n // 2 # 迭代次数、n为奇数时,矩阵的中心点
count = 1 # 计数
for offset in range(1, loop + 1) : # 每循环一层偏移量加1,偏移量从1开始
for i in range(starty, n - offset) : # 从左至右,左闭右开
nums[startx][i] = count
count += 1
for i in range(startx, n - offset) : # 从上至下
nums[i][n - offset] = count
count += 1
for i in range(n - offset, starty, -1) : # 从右至左
nums[n - offset][i] = count
count += 1
for i in range(n - offset, startx, -1) : # 从下至上
nums[i][starty] = count
count += 1
startx += 1 # 更新起始点
starty += 1
if n % 2 != 0 : # n为奇数时,填充中心点
nums[mid][mid] = count
return nums
标准代码二
使用了四个边界,没有用offset这个变量
class Solution(object):
def generateMatrix(self, n):
if n <= 0:
return []
# 初始化 n x n 矩阵
matrix = [[0]*n for _ in range(n)]
# 初始化边界和起始值
top, bottom, left, right = 0, n-1, 0, n-1
num = 1
while top <= bottom and left <= right:
# 从左到右填充上边界
for i in range(left, right + 1):
matrix[top][i] = num
num += 1
top += 1
# 从上到下填充右边界
for i in range(top, bottom + 1):
matrix[i][right] = num
num += 1
right -= 1
# 从右到左填充下边界
for i in range(right, left - 1, -1):
matrix[bottom][i] = num
num += 1
bottom -= 1
# 从下到上填充左边界
for i in range(bottom, top - 1, -1):
matrix[i][left] = num
num += 1
left += 1
return matrix
自己写的注意点记录
- python创建指定大小矩阵的方法:nums = [[0] * n for _ in range(n)]
- 思想:关于奇数和偶数的区别,自己想的时候想复杂了,奇数只要最后判别一下就行。其余的都是绕圈
- 关于第二圈开始的i,具体为每轮循环结束后i要不要减一,是debug才知道的
- 粗心:忘了平方和return
class Solution(object):
def generateMatrix(self,n):
"""
:type n: int
:rtype: List[List[int]]
"""
startx, starty = 0, 0
offset = 0
count = 1
i, j = 0, 0
nums = [[0] * n for _ in range(n)] # python初始化nxn矩阵的方法!!记住
epoch = 1
while (epoch <= n // 2):
# 先写第一行
for j in range(starty + offset, n - 1 - offset): # 第一条边从左往右
nums[i][j] = count
count += 1
j += 1 # 下一条边的起始位置应该是:之前没有包括的最后一个元素
for i in range(startx + offset, n - 1 - offset): # 第二条边从上往下
nums[i][j] = count
count += 1
i += 1
for j in range(n - 1 - offset, starty + offset, -1):
nums[i][j] = count
count += 1
j -= 1
for i in range(n - 1 - offset, startx + offset, -1):
nums[i][j] = count
count += 1
# i -= 1 #这里的i是不是要减一debug了一下
offset += 1
epoch += 1
if n % 2 == 1:
nums[n // 2][n // 2] = n * n # 最后忘了平方了
return nums # 忘了return
总结
今天组会效果还是不好,晚上错过了跟大老板的讨论,还是yy了一会儿,来不及第三题了,以后绝不会在没写完博客之前看手机。这么不顺利的时候心态真的很容易崩溃。