首页 > 编程语言 >算法打卡|Day2 数组part02

算法打卡|Day2 数组part02

时间:2023-09-22 18:55:39浏览次数:49  
标签:窗口 nums int 复杂度 part02 Day2 vector 数组 打卡

Day2 数组part02


今日任务:977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II


目录


Problem: 977. 有序数组的平方

思路

首先分析这道题,它是一道有序数组平方后排序的题目。观察平方后数组的特性我们发现,平方后最大的数永远是在数组的前后两端。例如【-1,-2,-3,0,1,2】,平方后去掉符号所以最大的数总是在两侧。
所以本题考虑运用前后双指针算法,一前一后两个指针,比较谁的值大就更新到新的数组中去,直到它们相遇(本题要求新数组从小到大,所以我们从后往前放大数)。

解题方法

双指针算法

复杂度

  • 时间复杂度:

$O(n)$
(补充:快排的时间复杂度:for循环:O(n) ✖️ 快排:O(nlogn))

Code


class Solution {
public:
  vector<int> sortedSquares(vector<int>& nums) {
      int k = nums.size() - 1;
      vector<int> newnums(nums.size(),0);//记住这种初始化操作,可以设置vector长度

      for(int j = nums.size()-1,  i = 0; i<=j;){
          if(nums[i]*nums[i] < nums[j]*nums[j]){
              newnums[k] = nums[j]*nums[j];
              k--;
              j--;
          } else{
              newnums[k] = nums[i]*nums[i];
              k--;
              i++;
          }
      }

      return newnums;

  }
};

Problem: 209. 长度最小的子数组

思路

1.前缀和+二分思路:观察到是求连续子数组的和的问题,我们可以用前缀和。首先我们对整个数组求前缀和数组,然后依次对前缀和数组每一项的值加上目标值去二分搜索不超过这个和的最小值那一项,这样得到的项便对应了连续子数组和的最后一项,我们用这一项减去遍历到的起始坐标,就得到了长度。然后依次遍历,依次比较最小长度即可。
2.双指针思路:其实写滑动窗口不需要背步骤,只需要写的时候问自己四个问题,而这四个问题也正是滑动窗口真正核心的部分。解决了这四个问题,代码也写出来了。

1.增大窗口时,要更新窗口内的什么数据?
要计算窗口内数字的和。

2.什么时候窗口要缩小(shrink)?
当窗口内的和大于等于目标长度时缩小。

3.窗口缩小时,更新窗口内的什么数据?
更新窗口长度,并与之前更新的长度比较得出最小长度。另外由于缩小窗口,在缩小窗口之前要先减去当前left指针所在的数值。

4.什么时候更新结果?
在循环缩小窗口的适合更新最小长度。

链接:https://zhuanlan.zhihu.com/p/142048740

解题方法

双指针算法|前缀和+二分

复杂度

  • 时间复杂度:

滑动窗口:$O(n)$
滑动窗口算法的时间复杂度通常是O(n) 的,其中 n 表示字符串或数组的长度。这是因为滑动窗口算法只需要对每个元素至多遍历一遍,同时也只需要在窗口的左右边界上移动,因此总的操作次数不会超过 2n 次。

前缀和+二分:$O(n+lgn)$

  • 空间复杂度:

$O(1)$

Code1:双指针


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

Code2:前缀和+二分


class Solution {
public:
  int minSubArrayLen(int target, vector<int>& nums) {
      int n = nums.size();
      vector<int> preSum(n + 1, 0);
      for(int i = 1; i <= n; i++) preSum[i] = preSum[i - 1] + nums[i - 1];

      int minSubArrayLen = INT_MAX;

      //每一项遍历搜索
      for(int i = 0; i< n; i++){
          int tar =target+preSum[i];
          int l = i-1;//区间范围搜索
          int r = n+1;//区间范围搜索
          while(l+1 != r){
              int mid =(l+r)/2;
              if(preSum[mid] < tar){
                  l = mid;
              } 
              else r = mid;
          }

          //输出答案时候注意过滤特殊情况
          if(l!=i-1 && r!=n+1 ) minSubArrayLen = min(minSubArrayLen, r - i);
      }
      return minSubArrayLen == INT_MAX ? 0 : minSubArrayLen;
  }
};


Problem: 59. 螺旋矩阵 II

思路

蛇形矩阵问题,我们可以用偏移量控制蛇的姿态,撞墙(越界)或重复走路代表着换方向。另外要注意边界条件,我们判断的是如果沿着当前方向走,下一步走出去了才换方向。

解题方法

利用 int dx[4] = {0, 1, 0, -1}和int dy[4] = {1, 0, -1, 0}去模拟四个方向的偏移量。

复杂度

  • 时间复杂度:

$O(n^2)$,取决于这个数组的大小

  • 空间复杂度:

$O(1)$

Code


class Solution {
public:
  vector<vector<int>> generateMatrix(int n) {
      vector<vector<int>> nums(n, vector<int>(n, 0));
      int x = 0, y = 0;

      //竖着看这是在模拟每个偏移量,分别是向上,向右,向下,向左
      int dx[4] = {0, 1, 0, -1};
      int dy[4] = {1, 0, -1, 0};
      
      //这是在记录方向,0。1。2。3代表取数组不同的方向
      int d = 0;

      for (int i = 1; i <= n * n; i++) {
          nums[x][y] = i;

          //这几步骤可以合并在一起,定义两个新的变量的目的是判断按着原来的方向继续走是否会撞墙或走了重复的路。
          int new_x = x + dx[d];
          int new_y = y + dy[d];
          if (new_x < 0 || new_x >= n || new_y < 0 || new_y >= n || nums[new_x][new_y] != 0) {
              d = (d + 1) % 4;//取模运算是一个周期函数,要记住,换方向就用取模运算,模几代表在几个数之间循环。
          }

          x = x + dx[d];
          y = y + dy[d];
      }
      return nums;
  }
};

标签:窗口,nums,int,复杂度,part02,Day2,vector,数组,打卡
From: https://www.cnblogs.com/RickRuan/p/17723168.html

相关文章

  • [代码随想录]Day51-单调栈part02
    题目:503.下一个更大元素II思路:总之就是走两次nums,可以拼接,也可以用下面的取余方式。代码:funcnextGreaterElements(nums[]int)[]int{lens:=len(nums)res:=make([]int,lens)fori:=0;i<lens;i++{res[i]=-1}stack:=make(......
  • Java(day20):泛型和枚举
    前言Java是一种面向对象的、跨平台的编程语言,在软件开发中应用广泛。在Java中,泛型和枚举是两种重要的特性,它们能够提高代码的可读性和重用性。本文将介绍Java泛型和枚举的概念、语法、使用方法、测试用例等方面。摘要泛型是Java的一种抽象类型,它允许使用者在编写代码时不指定数......
  • 921打卡
    1.N字形变换(06)将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z字形排列。比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:PAHNAPLSIIGYIR之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNA......
  • 每日打卡 周三 九月二十日
    今天就早上八点有一节课,完课后回到宿舍,最近有点感冒,大概10点到宿舍,躺在床上就睡过去了,起来就该吃午饭。下午本应该学习javaweb但是一直没有状态,只看了一会就感到头晕,躺在床上又睡过去了,起来天已经黑了,简单对付几口,吃过药就没有再出宿舍了。......
  • 9.20打卡带哨兵的双向环形链表
      importjava.util.ArrayList;//双向环形链表哨兵既是头也是尾哨兵的prev指向最后一个元素,最后一个元素的next指向哨兵publicclassMain{publicstaticvoidmain(String[]args){DoubleLinkedListd=newDoubleLinkedList();d.addFirst(3);......
  • 大二打卡(9.20)
    今天做了什么:英语课,今天帮英语老师擦了黑板,被老师感谢,开心,上课时候好多高中笔记本上记过的词汇短语都记不住汉语意思了,又是想念高中笔记本的一天,然后上节课讲的短语也没记住,只记得写在哪个位置了,可悲,今天遇到什么问题:英语小测试做题速度大不如前,没有写完全部题目,好多生词不认识......
  • 920打卡
    1.两数相加(02)给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字0之外,这两个数都不会以0 开头。思想:遍历,考虑进位和链表......
  • 打打卡
    9月19日:今天我学习了数据结构中的线性表的合并以及链表的合并,以及对栈有了一个初步的了解,虽然大概都听懂了,但是在课后学会在巩固、自己敲一遍相信会有更加深刻的理解。明天希望我能在空闲时间专心搞学习。......
  • 9月19每日打卡
    配置python开发环境Python可应用于多平台包括Linux和MacOSX。你可以通过终端窗口输入"python"命令来查看本地是否已经安装Python以及Python的安装版本。Unix(Solaris,Linux,FreeBSD,AIX,HP/UX,SunOS,IRIX,等等。)Win9x/NT/2000Macintosh(Intel,PPC,68K......
  • 大二打卡(9.19)
    今天做了什么:凌晨十二点半起床上厕所,心血来潮,看了眼12306,还真有29号的火车票了,虽然是无座票数据结构,今天讲到了栈结构,昨天王老师,包括大一时候的刘老师都经常提起,所以还是比较好理解的马原还是设计点哲学部分,不过比之前的什么形而上好理解点的部分晚上的白话文小说,老师讲的一如......