977.有序数组的平方(easy)
力扣链接
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
思路1 暴力求平方然后排序
直接使用python的sorted()函数。
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
new_nums = []
for i in range(len(nums)):
new_nums.append(nums[i]*nums[i])
new_nums = sorted(new_nums)
return new_nums
思路2 相向而行双指针
由于数组是非降序的,因此平方越大的值应该越靠近两端,不妨令两个指针一前一后筛查最大平方项,找到了就把他扔到新数组里面。又由于要求结果也要非降序,因此要从后往前放。
python创建全0数组:new_nums = len(nums)*[0]
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
new_nums = len(nums)*[0]
j = k = len(nums)-1 # j指向原数组的末尾,k指向新数组的末尾
i = 0 #头指针,指向原数组的开头
while i<=j:
print(i,j)
if(nums[i]*nums[i] < nums[j]*nums[j]):
#如果左边的小,则把右边的结果放到新数组k位置,并把j左移一位
new_nums[k] = nums[j]*nums[j]
j -= 1
else:
#如果左边的大,则把左边的结果放到新数组k位置,并把i右移一位
new_nums[k] = nums[i]*nums[i]
i += 1
k -= 1
return new_nums
209.长度最小的子数组(normal)
力扣链接
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
思路1. 暴力解法
搞两层循环,一个个去比较,但很可惜这个方法在处理长输入时力扣会判定超时
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
ret_nums = nums ## 用来记录最终返回的子序列
temp_nums = [] ## 用来记录当前循环得到的子序列,每次循环都更新
flag = False # 用来记录是否能找到子序列
for i in range(len(nums)):
num_sum = 0
j = i
while j<=len(nums)-1:
num_sum += nums[j]
if num_sum >= target: # 如果达成目的
flag = True
temp_nums = nums[i:j+1] # 取子序列,注意nums[,]是左闭右开的,要j+1
if len(ret_nums)>len(temp_nums):
# 如果当前temp_nums长度更短则更新入ret_nums
ret_nums = temp_nums
break
j += 1
if flag == False:
ret_nums = []
return len(ret_nums)
思路2. 滑动窗口
为了方便说明,我们在此规定滑动窗口整体从左到右滑动,左端指针称为“左脚”,右端指针称为“右脚”,滑动窗口即为左右脚之间夹着的区间。
其实,思路1的暴力解法也可认为是一种滑动窗口,这种方法用了两个循环。外层循环规定左脚位置,内层循环规定右脚位置,左脚作为立足点,右脚反复地向前试探。这样的滑动窗口效率太低。
因此,不妨让左脚活动起来,及时跟进右脚的步伐,而右脚则一往无前。
滑动窗口法的步骤为:
- 首先,让右脚一步步往前迈,左脚不动,同时统计双脚之间的和。
- 当和满足条件时,记录当前窗口中的子序列。然后左脚往前迈,缩小窗口。
- 在被缩小的窗口内再判断是否满足条件,如果满足,回到2.如果不满足,则让右脚继续向前。
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
n_sum = 0 #窗口内和
left = 0 # 窗口起始位置
right = 0 #窗口终止位置
temp_nums = []
ret_nums = nums
flag = False
while right < len(nums):
n_sum += nums[right]
# 当没找到子序列时,不断地迈右脚并把最新纳入的元素加上去
while n_sum >= target:
# 当找到子序列时,把当前子序列记下来,并让左脚跟上
flag = True
temp_nums = nums[left:right+1] # 获取子序列
n_sum -= nums[left] # 重新统计窗口内元素和
if len(temp_nums)<len(ret_nums):
ret_nums = temp_nums
left += 1
right +=1
if flag == False:
ret_nums = []
return len(ret_nums)
59.螺旋矩阵(normal)
力扣链接
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
思路
模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
而且每次循环的区间的开闭都要一致,这里采用左闭右开。
具体步骤如下:
- 首先定义几个重要的变量
行坐标为x,列坐标为y
nums = [[0] * n for _ in range(n)] # 用来创建一个n*n的二维数组
loop = n/2 用来定义要套几圈,如果是偶数,会正好套完,如果是奇数,最后会在中间留一个顽固分子
mid = n/2 如果是奇数,最中间残留的位置为nums[mid][mid]
startx ,starty 每次套圈的起始位置,即左上角
count 要放的元素,让他每次+1即可自动地从1到n*n置入
offset 从1开始每套完一圈+1,用n-offset来表示当前最右边的纵坐标和最下边的横坐标
- 写最上边
最上边的行坐标恒为startx,列坐标从左到右,即starty→n-offset - 写最右边
最右边的列坐标恒为n-offset,行坐标从上到下,即从startx→n-offset - 写最下边
最下边的行坐标恒为n-offset,列坐标从左到右,即从n-offset→starty - 写最左边
最左边的列坐标恒为starty,行坐标从下到上,即从n-offset→startx - 让起始位置偏移,进入下一次套圈
- 处理最中间的
class Solution(object):
def generateMatrix(self, n):
"""
:type n: int
:rtype: List[List[int]]
"""
nums = [[0] * n for _ in range(n)] # 构造一个n*n的二维数组
loop = n/2 # 要转几圈 当n为奇数时,中间只有一个空,那就不必循环了,直接填充n*n
mid = n/2 # 矩阵中间位置的横纵坐标
startx = starty = 0 # 每次转圈的左上角起始位置
count = 1
for offset in range(1,loop+1): #要从1开始,1~loop 用offset来控制边长
# n-offset表示当前最右边的纵坐标,最下边的横坐标
# 上边
for j in range(starty, n-offset): #左闭右开
nums[startx][j] = count
count += 1
# 右边
for i in range(startx, n-offset):
nums[i][n-offset] = count
count += 1
# 下边
for j in range(n-offset, starty, -1):
nums[n-offset][j] = 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:
nums[mid][mid] = count
print(nums)
return nums