977.有序数组的平方

题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/

文章讲解: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

卡哥的题目建议建议大家先独立做题,然后看视频讲解,然后看文章讲解,然后在重新做一遍题,把题目AC,最后整理成今日当天的博客,拓展题目可以先不做。本题关键在于理解双指针思想。

做题思路:

有两种方法,暴力解法和双指针法。非递减顺序就是递增顺序,从小到大排。

暴力解法思路:就是将数组中的每个数平方后,再按从小到大的顺序排序。C++的sort函数是基于快速排序实现的,函数原型 void sort(first,last),first是要排序的数组的起始地址,last是结束的地址(最后一个数据的后一个数据的地址)。如果利用迭代器,就可以用sort(a.begin(),a.end()),

 1 #include <iostream>
2 #include <algorithm>
3 using namespace std;
4 const int N = 10;
5 int a[N]; //声明全局数组
6 int main()
7 {
8 int n; //数组的元素个数为 n
9 cout << "请输入数组的元素个数:" << endl;
10 cin >> n;
11 cout << "请输入数组:" << endl;
12 for (int i = 0; i < n; i++)
13 {
14 cin >> a[i]; //循环输入数组中的元素
15 }
16 for (int i = 0; i < n; i++)
17 {
18 a[i] *= a[i];
19 }
20 sort(a,a+n); //注意:这里没有利用迭代器
21 for (int i = 0; i < n; i++)
22 {
23 cout << a[i] << " "; //循环输入数组中的元素
24 }
25
26 return 0;
27 }

运行结果:

双指针法思路:

先看给的数组,nums = [-4,-1,0,3,10],有负数;再平方后,nums = [16,1,0,9,100],观察到平方后的数组两边的数比中间的大,所以我们可以考虑从第一个位置向后开始,最后一个位置向前开始,比较谁大,如果最后一个位置的数大的话,那就把这个数存放到新数组中,随着第一个位置和最后一个位置的移动,就能实现排序,有移动的动图,在文章链接里。这个两个位置就可以用双指针解决,其实就是两个变量。

 1 #include <iostream>
2 using namespace std;
3 const int N = 10;
4 int a[N]; //声明全局数组
5 int main()
6 {
7 int n; //数组的元素个数为 n
8 cout << "请输入数组的元素个数:" << endl;
9 cin >> n;
10 cout << "请输入数组:" << endl;
11 for (int i = 0; i < n; i++)
12 {
13 cin >> a[i]; //循环输入数组中的元素
14 }
15 for (int i = 0; i < n; i++)
16 {
17 a[i] *= a[i];
18 }
19 int result[N];//放排好序的新数组
20 int k = n - 1; //新数组的下标为k,因为我们是先把大的数放进新数组,所以k值从n - 1开始
21 int first = 0;
22 int last = n - 1;
23 while (first <= last) //第一个位置的下标肯定比最后一个位置下标小或等于,才合法
24 {
25 if (a[first] < a[last])
26 {
27 result[k] = a[last];//最后一个位置比第一个位置大,就把最后一个位置的数放到新数组
28 k--; //比较完后,新数组的实际大小减一,更新下标
29 last--;//最后一个位置的数放到新数组,最后一个位置向前移动
30 }
31 else
32 {
33 result[k] = a[first];//第一个位置比最后一个位置大,
34 k--;//比较完后,新数组的实际大小减一,更新下标
35 first++;//第一个位置的数放到新数组,第一个位置向后移动
36 }
37 }
38 for (int i = 0; i < n; i++)
39 {
40 cout << result[i] << " "; //循环输入数组中的元素
41 }
42
43 return 0;
44 }

 运行结果:

209.长度最小的子数组

卡哥的题目建议本题关键在于理解滑动窗口,这个滑动窗口看文字讲解 还挺难理解的,建议大家先看视频讲解。  拓展题目可以先不做。

做题思路:

有两种方法,暴力解法和双指针法。

暴力解法思路:这个题是为了找到和大于某个值的长度最小的连续子数组,所以先找到和大于某个值的子数组集合,再找长度最小的。可以用两层for循环,外层循环先定好从哪个地方开始找子数组,内层循环求和,从下标为0的地方开始找和大于某个值的位置,如果和大于某个值,就先记录下这个位置到外层循环定好的位置之间的长度,后面的位置没有必要寻找了。然后开始下一轮外层循环,同理.......再记录,更新长度;直到外层循环完后,才能把最短长度求出来。所以暴力解法会超时。

 1 #include <iostream>
2 using namespace std;
3 const int N = 10;
4 int a[N]; //声明全局数组
5 int minSubArrayLen(int a[], int s)
6 {
7 int n = sizeof(a);
8 int result = INT32_MAX; // 最终的结果,INT32_MAX是int的最大值,2的16次方 - 1
9 int sum = 0; // 子数组的数值之和
10 int subLength = 0; // 子数组的长度
11 for (int i = 0; i < n; i++) //外层循环
12 {
13 sum = 0; //每一轮外层循环的时候,重置sum值,为了记录不同i值下的长度
14 for (int j = i; j < n; j++) //内层循环
15 {
16 sum += a[j];
17 if (sum >= s)//求和,从下标为0的地方开始找和大于某个值的位置
18 {
19 subLength = j - i + 1; //记录下这个位置到外层循环定好的位置之间的长度
20 result = result < subLength ? result : subLength;//如果小于最终长度,那最终长度不变;如果大于最终长度,那更新最终长度
21 break;
22 }
23 }
24 }
25 return result == INT32_MAX ? 0 : result;//如果result没有被赋值的话,就返回0,说明没有符合条件的子数组
26 }
27 int main()
28 {
29 int n; //数组的元素个数为 n
30 cout << "请输入数组的元素个数:" << endl;
31 cin >> n;
32 cout << "请输入数组:" << endl;
33 for (int i = 0; i < n; i++)
34 {
35 cin >> a[i]; //循环输入数组中的元素
36 }
37 int s;
38 cout << "请输入正整数 s :" << endl;
39 cin >> s;
40 cout << minSubArrayLen(a, s) << endl;
41 return 0;
42 }

运行结果:

双指针法思路:我们为了找到和大于某个值的长度最小的连续子数组,想像在数组上移动着找,刚开始会像暴力解法那样,定好一个起始位置,再移动另一个位置,但是如果两个位置都移动,效率就会提升很多,所以就引出了滑动窗口这个方法。在滑动窗口中,分起始位置和终止位置,终止位置用来找到和大于某个值的连续子数组集合;起始位置用来找最短长度,和暴力解法不同的是,当找到了和大于某个值的连续子数组集合后,就是终止位置暂时不移动了,同时记录下长度,起始位置此时从下标0开始移动,每移动一个位置,就用刚求好的和减去上一个位置的数,为了看还能不能找到更短的长度;如果不能的话,那只能移动终止位置,去重新找和大于某个值的连续子数组集合。同理,直到终止位置移动到数组尾部,且找不到最短长度了,就停止。

 1 #include <iostream>
2 using namespace std;
3 const int N = 10;
4 int a[N]; //声明全局数组
5 int minSubArrayLen(int a[], int s)
6 {
7 int n = sizeof(a);
8 int result = INT32_MAX; // 最终的结果,INT32_MAX是int的最大值,2的16次方 - 1
9 int sum = 0; //滑动窗口的数值之和
10 int subLength = 0; //滑动窗口的长度
11 int i = 0; //滑动窗口起始位置
12 for (int j = 0; j < n; j++)
13 {
14 sum += a[j];
15 // 注意这里使用while,每次更新 i(起始位置),并不断比较子数组是否符合条件
16 while (sum >= s) {
17 subLength = (j - i + 1); // 取子数组的长度
18 result = result < subLength ? result : subLength;
19 sum -= a[i]; // 这里体现出滑动窗口的精髓之处,不断变更i(子数组的起始位置)
20 i++; //起始位置向后移动
21 }
22 }
23 return result == INT32_MAX ? 0 : result;//如果result没有被赋值的话,就返回0,说明没有符合条件的子数组
24 }
25 int main()
26 {
27 int n; //数组的元素个数为 n
28 cout << "请输入数组的元素个数:" << endl;
29 cin >> n;
30 cout << "请输入数组:" << endl;
31 for (int i = 0; i < n; i++)
32 {
33 cin >> a[i]; //循环输入数组中的元素
34 }
35 int s;
36 cout << "请输入正整数 s :" << endl;
37 cin >> s;
38 cout << minSubArrayLen(a, s) << endl;
39 return 0;
40 }

运行结果:

59.螺旋矩阵II

     卡哥的题目建议本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。

     做题思路:

我感觉这里看视频和文章就能理解,就是要想到矩阵可以是一个正方形,从总共能走的圈数,再从正方形4条边入手,这些边可以当做在一个区间上,写一些区间上的边界的限制条件。结合之前做的题,会想到左闭右闭,左闭右开........

 1 #include <iostream>
2 using namespace std;
3 const int N = 10;
4 int main()
5 {
6 int n;
7 cout << "请输入一个正整数 n:" << endl;
8 cin >> n;
9 int res[N][N] = { 0 };
10 int startx = 0, starty = 0; // 定义每循环一个圈的起始位置,相当于一个坐标(startx, starty)
11 int loop = n / 2; // 这个可以画图理解,每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
12 int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
13 int count = 1; // 用来给矩阵中每一个空格赋值
14 int offset = 1; // 每一圈右边界向里收缩一位
15 int i, j;
16 while (loop--)
17 {
18 i = startx;
19 j = starty;
20
21 // 下面开始的四个for就是模拟转了一圈
22 // 模拟填充上行从左到右(左闭右开)
23 for (j = starty; j < n - offset; j++) //行不变,列变,所以列的初始值一开始为0,右开,右边界值不能取到
24 {
25 res[startx][j] = count++;
26 }
27 // 模拟填充右列从上到下(左闭右开)
28 for (i = startx; i < n - offset; i++) //列不变,行变,所以行的初始值一开始为0,右开,右边界值不能取到
29 {
30 res[i][j] = count++;
31 }
32 // 模拟填充下行从右到左(左闭右开)
33 for (; j > starty; j--) //走到了i, j 的最大值处,不需要设行列的初始值,行不变,列变,列不能比0小
34 {
35 res[i][j] = count++;
36 }
37 // 模拟填充左列从下到上(左闭右开)
38 for (; i > startx; i--)//走到了 i 的最大值处........
39 {
40 res[i][j] = count++;
41 }
42
43 // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
44 startx++;
45 starty++;
46
47 // offset 控制每一圈里每一条边遍历的长度
48 offset += 1;
49 }
50
51 // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
52 if (n % 2 == 1)
53 {
54 res[mid][mid] = count;
55 }
56 for (int i = 0; i < n; i++) //矩阵为 n*n
57 {
58 cout << "[";
59 for (int j = 0; j < n; j++)
60 {
61 cout << res[i][j] << " ";
62 }
63 cout << "]";
64 cout << endl;
65 }
66 return 0;
67 }

      运行结果:

最后,数组的总结看一下卡哥的吧。

代码随想录算法训练营第二天| LeetCode 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II的更多相关文章

  1. 代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

    977.有序数组的平方 :https://leetcode.cn/problems/squares-of-a-sorted-array/ 心得:周末再写... public class Solutio ...

  2. 代码随想录训练营day 2 |977有序数组的平方 209.长度最小的子数组 (C++)

    977.有序数组的平方 题目链接:977.有序数组的平方 题目描述:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序. 例子如下: 输入 ...

  3. 代码随想录第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

    2022/09/22 第二天 第一题 这题我就直接平方后排序了,很无脑但很快乐啊(官方题解是双指针 第二题 滑动窗口的问题,本来我也是直接暴力求解发现在leetCode上超时,看了官方题解,也是第一次 ...

  4. Leetcode 209.长度最小的子数组 By Python

    给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组.如果不存在符合条件的连续子数组,返回 0. 示例: 输入: s = 7, nums = [2, ...

  5. LeetCode 209. 长度最小的子数组(Minimum Size Subarray Sum)

    题目描述 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组.如果不存在符合条件的连续子数组,返回 0. 示例: 输入: s = 7, nums ...

  6. Java实现 LeetCode 209 长度最小的子数组

    209. 长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组.如果不存在符合条件的连续子数组,返回 0. 示例: 输入: s = ...

  7. 【LeetCode】209. 长度最小的子数组

    209. 长度最小的子数组 知识点:数组:前缀和:二分法:双指针:滑动窗口 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target . 找出该数组中满足其和 ≥ target 的长度最小 ...

  8. 代码随想录训练营day 3|59.螺旋矩阵II 加 数组总结篇

    59.螺旋矩阵II 题目链接:59.螺旋矩阵II 题目描述:给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵. 示例: 输入: 3 输出: [ [ 1 ...

  9. LeetCode:长度最小的子数组【209】

    LeetCode:长度最小的子数组[209] 题目描述 给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组.如果不存在符合条件的连续子数组,返回 ...

  10. leetcode 54. 螺旋矩阵 及 59. 螺旋矩阵 II

    54. 螺旋矩阵 问题描述 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素. 示例 1: 输入: [ [ 1, 2, 3 ], [ 4, 5, ...

随机推荐

  1. 实现异步操作CompletableFuture

    多个线程异步操作后统一返回执行结果AtomicReference<RespVo> event = new AtomicReference<>(); AtomicReferenc ...

  2. shell基本命令与参数

    1:一行可以有多个命令,用";"分开 如: cd ..; ls -l 2:先项用"-"开始,多个连接可连在一起,如:ls -lh, 3:"--&quo ...

  3. Python表达式及运算符

    表达式 由一个或者几个数字或者变量或者运算符合成的一行代码 通常返回一个结果 运算符 由一个以上的值经过一系列的运算得到新值的过程叫运算 用来操作运算的符号叫运算符 运算符分类 算数运算符 比较或者关 ...

  4. #Python基础 pandas索引设置

    一:XMIND 二:设置索引 示例数据,假设我们有一个DataFrame对象,如下: import pandas as pd df = pd.DataFrame({ "name": ...

  5. SpringBoot集成Jpa对数据进行排序、分页、条件查询和过滤

    之前介绍了SpringBoot集成Jpa的简单使用,接下来介绍一下使用Jpa连接数据库对数据进行排序.分页.条件查询和过滤操作.首先创建Springboot工程并已经继承JPA依赖,如果不知道可以查看 ...

  6. 2021-10-24:快乐数。编写一个算法来判断一个数 n 是不是快乐数。「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是

    2021-10-24:快乐数.编写一个算法来判断一个数 n 是不是快乐数.「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和.然后重复这个过程直到这个数变为 1,也可能是 ...

  7. 2022年第十四届四川省大学生程序设计大赛 A

    A Adjacent Swapping 题意: 给定一个字符串,每次可以移动相邻字符,求最小移动次数可以把它变成s+s这样左右两边相同的字符串. 思路: 1:我们知道他一定是偶数长度,所以我们把字符串 ...

  8. 与世界分享我刚编的mysql http隧道工具-hersql原理与使用

    原文地址:https://blog.fanscore.cn/a/53/ 1. 前言 本文是与世界分享我刚编的转发ntunnel_mysql.php的工具的后续,之前的实现有些拉胯,这次重构了下.需求背 ...

  9. Github疯传!200本计算机经典书籍!

    好书在精不在多,每一本经典书籍都值得反复翻阅,温故而知新! 下面分享几本计算机经典书籍,都是我自己看过的. 重构 改善既有代码的设计 就像豆瓣评论所说的,看后有种醍醐灌顶.欲罢不能的感觉.无论你是初学 ...

  10. HA高可用集群部署

    HA高可用集群部署 高可用 ZooKeeper 集群部署 zookeeper安装部署 注意:需要安装jdk,但jdk已经在第4章装过,这里直接装zookeeper #解压并安装zookeeper [r ...