完成977有序数组的平方,209长度最小的子数组,59螺旋矩阵。拓展题目二刷做。
题目描述: 给你一个按非递减顺序排序的整数数组 nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序
输入: nums = [-4,-1,0,3,10]
输出: [0,1,9,16,100]
解释: 平方后,数组变为 [16,1,0,9,100];排序后,数组变为 [0,1,9,16,100]
题目链接: https://leetcode.cn/problems/squares-of-a-sorted-array/
解题思路
1 暴力解法
**暴力解法python实现**
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
new_nums = [];
for i in range(len(nums)):
temp = nums[i] * nums[i];
new_nums.append(temp);
new_nums.sort();
return new_nums;
2 双指针法
**双指针解法python实现**
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
new_nums = [0]*len(nums);
k = len(nums) - 1; # 控制新数组从后往前填入元素
p = 0; # 左指针
q = k; # 右指针
for i in range(k, -1, -1):
if p == q: # 临界条件:p == q 时代表旧数组已经遍历完毕,可以退出循环
new_nums[i] = nums[p]*nums[p];
break;
if nums[p]*nums[p] >= nums[q]*nums[q]:
new_nums[i] = nums[p]*nums[p];
p += 1;
else:
new_nums[i] = nums[q]*nums[q];
q -= 1;
return new_nums;
3 心得体会
看到本题的第一想法就是暴力求解,没有考虑双指针。感觉是看了题目就觉得可以暴力求解,就没有思考这个题目给出的数据的特殊性,从而没有考虑到更快的方法。希望以后能看到题目后先想想会不会有更好的方法再去写代码,而不是一味的图做完题就可以。
昨天今天的题目均用到双指针解法,昨天的移除元素是同方向的双指针,今天是相向的双指针,双指针法在数组中很常见,以后应该多考虑这种方法。
题目描述: 给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [ n u m s , n u m s l + 1 , . . . , n u m s r − 1 , n u m s r ] [nums,nums_{l+1},...,nums_{r−1},nums_{r}] [nums,numsl+1,...,numsr−1,numsr],并返回其长度。如果不存在符合条件的子数组,返回 0
输入: target = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的子数组
题目链接: https://leetcode.cn/problems/minimum-size-subarray-sum/
解题思路
1 暴力解法
**暴力解法c++实现**
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX; // 最终的结果
int sum = 0; // 子序列的数值之和
int subLength = 0; // 子序列的长度
for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
sum = 0;
for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
sum += nums[j];
if (sum >= s) { // 一旦发现子序列和超过了s,更新result
subLength = j - i + 1; // 取子序列的长度
result = result < subLength ? result : subLength;
break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
}
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result == INT32_MAX ? 0 : result;
}
};
**暴力解法python实现**
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
sub_nums = [];
for i in range(len(nums)): # 控制子数组长度
for j in range(len(nums)): # 遍历该长度下的所有子数组
sub_nums = nums[j:j+i+1];
if sum(sub_nums) >= target:
return i+1;
return 0;
2 滑动窗口解法
**滑动窗口法python实现**
class Solution(object):
def minSubArrayLen(self, target, nums):
"""
:type target: int
:type nums: List[int]
:rtype: int
"""
i = 0;
sum = 0; # 窗口内元素之和
result = sys.maxint; # 定义最大值,以便于更新result
for j in range(len(nums)): # j为后指针,可以减少复杂度
sum += nums[j];
while(sum >= target):
# 此处用循环因为要确定以后指针为终点的最小窗口值,i可能要向后移动几个位置
sub_length = j-i+1; # 窗口内元素个数
if sub_length < result:
result = sub_length;
sum -= nums[i]; # 前指针滑动,窗口内元素和需要减去前指针指向的值
i += 1; # 前指针滑动以确定以后指针为终点的最小窗口值
if result == sys.maxint:
return 0;
else:
return result;
理解:
暴力解法是找出所有以每一个位置为起始符合条件的最小子数组,再比较这些子数组的长度,找出最小长度返回
滑动窗口法是找出以窗口终止位置为终点符合条件的最小子数组,再比较这些子数组的长度,找出最小长度返回
暴力解法两层循环,显然复杂度为O( n 2 n^2 n2)
滑动窗口法可以分析,外层循环 j j j是 n n n,内循环 i i i最多运行 j − i j-i j−i次,所以复杂度为O( ( j − i ) ∗ n (j-i)*n (j−i)∗n),故为O( n n n)
思考一下两种算法的过程,可以很清晰的感觉到暴力解法很多搜索过程是没必要的,比如以第一个元素为起始的符合条件的子数组区间为【0,4】,那对于第二个元素就没有必要搜索【1,1】【1,2】【1,3】【1,4】这些位置了,而滑动窗口法就是把这些不必要再去搜索的枝剪掉了
3 心得体会
看到这道题的第一想法就是暴力求解,但是力扣会报超时,还思考了不少时间,当时想到一个找包含最大元素的最短子序列,但是今天想想这种想法应该是不对的,因为题目中有连续二字,所以最短子序列是不一定包含最大元素的,以后要好好审题,不然耽误时间
这道题运用了滑动窗口法去降低时间复杂度,第一次接触到,今后要再好好思考滑动窗口的使用条件以及怎么用
题目描述: 给定一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix
输入: n = 3
输出: [[1,2,3],[8,9,4],[7,6,5]]
题目链接: https://leetcode.cn/problems/spiral-matrix-ii/
解题思路
1 代码实现
**python实现**
class Solution(object):
def generateMatrix(self, n):
"""
:type n: int
:rtype: List[List[int]]
"""
matrix = [[0] * n for _ in range(n)]
left, right, up, down = 0, n - 1, 0, n - 1
number = 1 # 要填充的数字
count = 0 # 转圈数
while count < n // 2:
# 从左到右填充上边
for x in range(left, right):
matrix[up][x] = number
number += 1
# 从上到下填充右边
for y in range(up, down):
matrix[y][right] = number
number += 1
# 从右到左填充下边
for x in range(right, left, -1):
matrix[down][x] = number
number += 1
# 从下到上填充左边
for y in range(down, up, -1):
matrix[y][left] = number
number += 1
# 缩小要填充的范围
left += 1
right -= 1
up += 1
down -= 1
count += 1
# 如果阶数为奇数,额外填充一次中心
if n % 2:
matrix[n // 2][n // 2] = number
return matrix
**随想录python实现**
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
2 心得体会
这个题没有自己认真写,模拟过程总觉得很麻烦,看了视频课,重点在于循环不变量原则。希望二刷时候不要懒惰,自己好好写一次。
今天掌握了双指针法,滑动窗口法以及模拟类题目的一些需要注意的地方。重点体会了滑动窗口法,以后还得多看多思考这部分。
到这里,数组部分的练习题结束了,放假的那天记得写一个数组部分的总结。
进度还是慢了一个博客,希望明天能补回来TwT。