977.有序数组的平方
题目:给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
暴力排序
先平方再排序,刚开始犯了几个小错误:
1. 平方计算是num**2或者pow(num,2)
2. python排序函数是sort(),默认升序,reverse = ture降序
解出来如下:
class Solution(object):
def sortedSquares(self, nums):
nums_out = []
for i in range(len(nums)):
nums_out.append(nums[i]**2)
nums_out.sort()
return nums_out
时间复杂度:O(n+nlogn)
双指针法
用处:数组是有序的, 只不过有负数,数组平方的最大值就在数组的两端
方法: i指向起始位置,j指向终止位置;定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置
如果A[i] * A[i] < A[j] * A[j]
那么result[k--] = A[j] * A[j];
。
如果A[i] * A[i] >= A[j] * A[j]
那么result[k--] = A[i] * A[i];
。
看完思路后写出代码出现一点小问题:
1. while i <= j 不能写成i>0 and j<l,要保证双指针位置
2. 想import numpy创建数组有点问题nums_out = np.empty(l,dtype = float)
最终如下:
class Solution(object):
def sortedSquares(self, nums):
l = len(nums)
nums_out = [float('inf')]*l
k = l-1
i = 0
j = l-1
while i <= j:
if nums[i]**2 <= nums[j]**2:
nums_out[k] = nums[j]**2
j -= 1
else:
nums_out[k] = nums[i]**2
i += 1
k -= 1
return nums_out
时间复杂度:O(n)
看了解析python还有一个暴力排序法+列表推导法:
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
return sorted(x*x for x in nums)
209.长度最小的子数组
题目:给定一个含有 n
个正整数的数组和一个正整数 target
。找出该数组中满足其总和大于等于 target
的长度最小的连续子数组[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
暴力解法
超出时间限制了:
class Solution(object):
def minSubArrayLen(self, target, nums):
l = len(nums)
result = l+1
for i in range(l):
s = 0
for j in range(i,l):
s += nums[j]
if s >= target:
out_l = j-i+1
result = min(out_l, result)
break
if result == l+1: result = 0
return result
几个注意的语法问题:
1. 这里的result可以定义为float('inf')好像蛮常用的
2. 条件满足直接break
3. 最后的判断可以写得更简洁
return min_len if min_len != float('inf') else 0
时间复杂度:O(n^2)
空间复杂度:O(1)
滑动窗口
滑动窗口:在于根据当前子序列和大小的情况,不断调节子序列的起始位置
只用一个for循环,那么这个循环的索引,一定是表示滑动窗口的终止位置
确定三点:
窗口:满足其和 ≥ s 的长度最小的连续子数组
窗口的起始位置:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)
窗口的结束位置:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引
关键在于对窗口起始位置的移动,减去sum里的值
刚开始是这么写的:
class Solution(object):
def minSubArrayLen(self, target, nums):
l = len(nums)
result = float('inf')
i = 0
s = 0
for j in range(l):
s += nums[j]
if s >= target:
out_l = j-i+1
result = min(out_l, result)
s -= nums[i]
i += 1
if result == float('inf'): result = 0
return result
出现了问题,问了gpt才知道:
用if 对s进行判断,对窗口减去值只进行了一次,例如,如果target
是7,数组是[2,3,1,2,4,3]
,当窗口扩展到包含前五个元素时,总和为12,这时仅仅减去窗口的第一个元素(即2)并向前移动i
一次,可能并不足以使窗口的和小于target
,而是应该继续移动i
直到窗口的总和再次小于target
,然后再次尝试扩展窗口来寻找可能的更小的满足条件的窗口。
所以这里应该使用一个while
循环来不断地尝试缩小窗口的大小(即移动i
),直到窗口的总和小于target
为止,然后再继续尝试扩展窗口。这样可以确保总是找到最小长度的满足条件的子数组。
修改如下:
class Solution(object):
def minSubArrayLen(self, target, nums):
l = len(nums)
result = float('inf')
i = 0
s = 0
for j in range(l):
s += nums[j]
while s >= target:
out_l = j-i+1
result = min(out_l, result)
s -= nums[i]
i += 1
if result == float('inf'): result = 0
return result
时间复杂度:O(n)
空间复杂度:O(1)
59.螺旋矩阵II
题目:给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
刚拿到毫无思路www,转头去看解析。
坚持循环不变量原则
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
说的很好,但是本菜鸟还是没懂,去看了眼代码,自己写了一遍:
class Solution(object):
def generateMatrix(self, n):
matrix = [[0 for i in range(n)] for i in range(n)]
loop = n//2
center = n//2
x = 0
y = 0
count = 1
for offset in range(1,loop+1):
for i in range(y,n-offset):
matrix[x][i] = count
count += 1
for i in range(x,n-offset):
matrix[i][n-offset] =count
count += 1
for i in range(n-offset,y,-1):
matrix[n-offset][i] = count
count += 1
for i in range(n-offset,x,-1):
matrix[i][y] = count
count += 1
x += 1
y += 1
if n%2 != 0: matrix[center][center] = count
return matrix
刚开始犯了个错误,for逆循环的时候没有加-1步长,导致range
的起始值大于结束值,而默认步长为 1
,这意味着循环体不会被执行。
时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
空间复杂度 O(1)
数组总结
二分法:循环不变量原则
双指针法:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作
滑动窗口: 根据当前子序列和大小的情况,不断调节子序列的起始位置
模拟行为:循环不变量原则