代码随想录算法训练营day2| leetcode977有序数组的平方、209长度最小的子数组、59螺旋矩阵

1.原题:leetcode977有序数组的平方

【暴力解法】直接循环遍历所有的数组元素,将它们挨个平方,然后再进行升序排列。

源代码如下:

【收获1】对数组进行排序时可以使用sort函数

sort(Array.begin(),Array.end());

【收获2】数组中的push_back()函数的使用方法

vector<int>ans;//定义一个新的容器ans用来储存平方后的数字

for(int i=0;i<nums.size();i++)
{
  ans.push_back(nums[i]*nums[i]);  //在这里ans.push_back()可以让括号里运算出的结果直接存放进 
                                    //容器ans 
                                    //的当前索引对应的位置。实际上,push_back()函数的定义是在 
                                     数 
                                    //组的末尾索引+1对应的索引位置处储存新的数据,但是当前ans容 
                                      器 
                                    //内是空的,所以从最开始开始存储
}

完整暴力求解代码:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
    vector<int>ans;
   for(int i=0;i<nums.size();i++)
   {
       ans.push_back(nums[i]*nums[i]);
   }
   sort(ans.begin(),ans.end());
   return ans;
    }
};

【双指针法求解】

定义左右两个指针i,j分别从数组的左右两端进行移动,每次都移动一位,先计算当前位置的元素的平方,比较当前左右指针所在位置的元素的平方,大的就把它放到result[k],同时k--,让result的倒数下一个位置等待赋值;然后移动被用于赋值的元素位置处的指针,i++或者j--同时另一个指针暂时不动,等待和移动后的指针所指向的元素进行比较。

源代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
     int k=nums.size()-1;
     vector<int>result(nums.size(),0);
     for(int i=0,j=nums.size()-1;i<=j;)
     {
        if(nums[i]*nums[i]>=nums[j]*nums[j])
        {result[k--]=nums[i]*nums[i];
         i++;
        }
        else
        { result[k--]=nums[j]*nums[j];
        j--;
        }
     }
     return result;
     
    }
};

2.原题:leetcode209长度最小的子数组

【暴力求解】写双重循环,第一重找到子序列的起始下标,第二重找子序列的末尾下标,定位一个子数组后就求和,

【收获3】C++中的INT_MAX和INT_MIN是两个预定义宏,代表了整型变量所能存储的最大和最小负整数,分别为2147483647和-2147483648,可以视为int中的无穷大和无穷小

在本题中用到了

int ans = INT_MAX;
return ans == INT_MAX ? 0 : ans;

暴力求解的源代码如下:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
     
    int n = nums.size();
    if(n==0)        //当数组大小为0时,就直接返回0
    {
        return 0;
    }

    int ans = INT_MAX;    //定义ans为无穷大的数
    for(int i = 0;i<n;i++)    //定位子数组的左侧初始下标
    {
        int sum=0;            //定义sum用来存储子数组的和
         for(int j=i;j<n;j++)//定位子数组的末下标
         {
             sum += nums[j];  //求子数组的和
              if(sum >= target)  //当子数组的和大于或等于给定的target时,就结束查询
              {
                  ans = min(ans,j - i + 1);/*每求一次满足if中条件的一个数组,就对这个所找到的*/
                  break;
              }                                / *  子数组,就求一次它的区间大小,和上一次找到的进行比较,将最小的最终保存到ans中,跳出内循环*/
         }
    }
return ans == INT_MAX?0 : ans;//有可能最后ans一直都是初始值INT_MAX在遍历中并没有得到更新。所以要进行最后一次判断,如果没更新过,就表明数组中不存在满足条件的子数组,就让返回值为0。更新过了,就让返回值为ans;
    }
};

【滑动窗口求解】本质上也可理解为双指针,滑动窗口是一种形象化的说法,我们本质上是定义了两个指针start 和end,通过移动两个指针来改变“窗口”(数组)的大小和位置。每次滑动这个窗口就进行一次求和,与前一次的和进行比较,如果比较小就更新,比较大就进入下一轮的求和计算,这里和暴力求解思路有点类似,不同的地方在于我们借助指针start的移动,避免了部分重复,减少了运算的数据规模。(每更新一次和,就将这个数组的start往前移动一位,start++,去掉第一个数组元素)。返回时再进行一次判断,看有没有真的实现更新,这个和暴力求解时说的一样。

完整求解代码如下:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
     int n=nums.size();
     int ans=INT_MAX;
     int start=0,end=0;
     int sum=0;
   
    while(end<n)
    {
      sum+=nums[end];
      while(sum >= target)
      {
        ans=min(ans,end-start+1);
        sum -= nums[start];
        start++;
      }
      end++;
    }
    return ans==INT_MAX? 0 : ans;
    }
};

3.原题链接:leetcode59螺旋矩阵

【收获4】区间的定义和使用原则要统一;比如都是用左闭右开。

【题解思路】

先定义每个循环圈的起始位置(startx,starty),要考虑到行列数是奇数还是偶数,这决定了有几个圈,如果是奇数,最后一个圈实际上就是一个元素,可以不参与循环单独处理,如果是偶数就不存在这最后一个元素,可以全部用循环来计算和赋值。

int loop = n / 2 ;//loop,每个圈循环几次,比如n=3,那么loop=1只是循环一圈,最中间的元素单独处理

以第一圈为例,我们先填充top第一行,填充范围是(0,n-1),此时变的是列标 j 的值; 

for(j = starty; j< n - offset; j++)//这里用offset不直接用1是因为进入下一层循环时,被赋值的数组元素个 
                               //数会减少一个。每完成一次循环就需要减1;
{
  res[i][starty]=count++;//这里的count初始值为1,每次+1,用来给数组中每一个元素赋值
}

然后填充右侧第一列,填充范围是(0,n-1),此时变的是行标 i 的值。

for(i = startx;i < n - offset; i++)
{
  res[startx][j]=count++;        //这里之所以再另外设置一个startx,一个starty,是因为每进行完一圈
                                   //  的赋值,就需要缩小这个数组行列的边界一次.
}

再填充底部最后一行,从右往左,填充范围是(0,n-1),此时变的是列标 j 的值。

for(; j>0;j--)
{
  res[i][j]=count++;
}

第一圈的最后给左侧第一列从下往上赋值,填充范围是(0,n-1),此时变的是行标 i 的值

for(; i>0; i--)
{
  res[i][j]=count++;
}

每次结束一圈,就进行一次边界缩小

startx++;
starty++;
offset +=1;//每次需要被n减去的值要增加一个

另外要在循环结束后记得判断一下是不是奇数行列,如果是奇数,会留下一个最中间的位置等待赋值。

if(n%2!=0)
{
   res[mid][mid]=count;//这里不是count++;count++的意思是先给count位置处赋值,然后让count++,前面 
                             //的循环已经让它+1了。
}

完整求解代码如下:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
    vector<vector<int>>res(n,vector<int>(n,0));
    int startx=0,starty=0;
    int loop=n/2;
    int mid = n / 2;
    int count = 1;
    int offset = 1;
    int i,j;
    while (loop --){
        i = startx;
        j = starty;

        for(j = starty;j<n - offset; j++){
            res[startx][j] = count++;
        }

        for(i = startx;i<n-offset; i++)
        {
            res[i][j]=count++;
        }
        for(;j>starty;j--){
            res[i][j]=count++;
        }
        for(;i>startx;i--)
        {
            res[i][j]=count++;
        }
        startx++;
        starty++;
        offset += 1;
    }

      if(n%2!=0)
      {
          res[mid][mid]=count;
      }
      return res;
    }
};

【收获5】用vector定义二维数组,同时使用已有的一维数组范围。

vector<vector<int>>res(n,vector<int>(n,0));

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值