代码随想录Day02| 有序数组的平方 长度最小的子数组 螺旋矩阵II
1.题目链接:有序数组的平方
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep
状态:已完成
题目描述:给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
解题思路:
按照题目给的顺序,想了几种解法,一种是先进行平方,平方完后进行排序来解,第二种是把负数变为正数后进行排序,排序完后进行平方得到的数组即为正确答案。感觉第一种和第二种的时间和空间消耗应该都不小,但第一种写起来可能更加的简单,于是选择了第一种解法。
在经过学习后发现该题可以使用双指针的方法来写。因为数组是一个非递减的有序数组,且有正有负。在两边都进行平方后,正常情况下都是大的在两边,小的在中间。也就是从两边往中间收缩。这个时候可以使用双指针的方式来解这道题。
1.暴力解法(先平方后排序(冒泡排序))
使用一个for循环,将数组里面的数先平方。接着使用冒泡排序(本来是想使用快速排序的,但一下子忘记了快速排序的算法,稍后去复习一下)的排序算法进行排序
下面是代码示例:
class Solution {
public int[] sortedSquares(int[] nums) {
for(int i=0;i< nums.length;i++){
nums[i]=nums[i]*nums[i];
}
int temp;
for(int i=0;i< nums.length;i++){
for(int j=1;j< nums.length-i;j++){
if(nums[j]<nums[j-1]){
temp=nums[j];
nums[j]=nums[j-1];
nums[j-1]=temp;
}
}
}
return nums;
}
}
把这个答案放到力扣去提交后,发现果然需要花费较长的时间和空间
2.双指针解法
用到双指针,那肯定是需要定义两个指针的。 定义一个左指针l=0,右指针r=nums.length-1。同时还需要开辟一个新的数组来进行储存,否则在更新元素的时候,会将标记的数给覆盖掉。左指针与右指针进行比较,较大的放在数组的最后面,并移动指针(左边的向后移,右边的向前移)。循环结束的条件为l>r,即while(l<=r)
下面是代码示例:
class Solution{
public int[] sortedSquares(int[] nums){
//l为左指针,r为右指针,k用来记录当前新数组存放元素的位置
int l=0,r= nums.length-1,k= nums.length-1;
int[]res =new int[nums.length];
while(l<=r){
int m=nums[l]*nums[l],n=nums[r]*nums[r];
if(m>n){
res[k--]=m;
l++;
}
else{
res[k--]=n;
r--;
}
}
return res;
}
}
总结:
遇到非递减需要排序的数组时,可以多考虑需要用到二分法的情况。目前所学习的用到二分的情况,二分排序,移除元素,以及有序数组平方的排序。做题的时候还是需要多去思考和总结
2.题目链接:长度最小的子数组 - 力扣
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
状态:已完成
题目描述:给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度**。**如果不存在符合条件的子数组,返回 0
。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
解题思路:
因为练习的不多,所以刚看到这道题目的时候觉得这道题目有较大的难度。但在尝试写的过程中,发现只需要把多种可能发生的情况进行全面的思考。并学会去运用标记点,便能够很好的做出这道题。详细的解题思路我就不赘述了,看代码也能够get到。一开始理解错题目,以为一定要等于才可以,后面发现时大于等于就可以了,所以整一个代码可能会有一点复杂。
后面通过看视频和看文章进行了学习。发现使用滑动窗口即与前面所学习的双指针的方法,便可以较为简单的解出这道题。
1.暴力解法
代码示例如下:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum=0,k= nums.length,m=0,min= nums.length,flag=0;
int i=0,count=0;
while(i<=k&&m<k){
while (sum<target&&i<k){
sum+=nums[i];
i++;
count++;
if(i>=k){
if(flag==0){
min=0;
}
break;
}
}
if(sum>=target){
flag=1;
if(count<min||min==0){
min=count;
}
}
sum-=nums[m++];
count--;
}
return min;
}
}
2.滑动窗口(双指针)
双指针确定好起始位置与终止位置。利用双指针,一个表示起始位置,另一个表示终止位置。相当于一个滑动窗口,需要搜集窗口的和。当和大于等于目标数时,就将窗口的长度记录下来,接着再将起始位置往后移一个,进行此操作的时候记得要将不在窗口里面的前一个起始位置的数减掉。
下面是代码示例:
class Solution{
public int minSubArrayLen(int target, int[] nums){
int sum=0,i=0,result=Integer.MAX_VALUE;
for(int j=0;j<nums.length;j++){
sum+=nums[j];
while(sum>=target){
result=Math.min(result,j-i+1);
sum-=nums[i++];
}
}
return result==Integer.MAX_VALUE ? 0 : result;
}
}
总结
自己的思路跟最后比较简洁的方法的思路相差还是很小的,就是在思考条件限制方面,不能偶用比较简洁的代码表示出来,这一点还是有待提高的。对于双指针的运用也不是非常的熟练。
3.题目链接:螺旋矩阵 II - 力扣
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/
状态:已完成
题目描述:给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
解题思路
需要理解的是螺旋排列的正方形矩阵,她是如何画出来的,根据正方形矩阵的排列,我们不难找出相应的规律。画矩阵的过程应该是这样的:填充上行从左到右,填充右列从上到下,填充下行从右到左,填充左列从下到上。根据这样的规律,由外向内一圈一圈的画下去。
找到这样的规律后,我们还要思考一个统一的条件,不然在写的时候就很容易出现重复的情况,那就好的方法就是每一行区间都使用左开右闭的方法。
代码示例如下:
class Solution3{
public int[][] generateMatrix(int n){
int loop=0; //控制循环的次数
int[][] res=new int[n][n];
int start=0; //循环的开始点
int count=1; //填充的数字
int i,j;
while(loop++<n/2){
//模拟上侧从左到右
for(j=start;j<n-loop;j++){
res[start][j]=count++;
}
//模拟右侧从上到下
for(i=start;i<n-loop;i++){
res[i][j]=count++;
}
//模拟下侧从右到左
for(;j>=loop;j--){
res[i][j]=count++;
}
//模拟左侧从下到上
for(;i>=loop;i--){
res[i][j]=count++;
}
start++;
}
if(n%2==1){
res[start][start]=count;
}
return res;
}
}
总结:
这道题其实并不是很难,在算法方面没有什么难度,就是需要我们去找到规律并理清条件。
体会:
今天预留做题的时间没有很多,最后一题没有留足够多的时间让自己去思考。而是先看了大体的思路再去思考。不利于提高自己的编程能力,希望后面的学习时间里面给自己预留足够的时间进行学习。多思考多练习!