01_数组_03_非递减数组的平方

https://leetcode.cn/problems/squares-of-a-sorted-array/description/

内容

给你一个按 非递减顺序 排序的整数数组 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 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 已按 非递减顺序 排序

进阶:

  • 请你设计时间复杂度为 O(n) 的算法解决本问题

代码(后边界起遍历)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
vector<int> newnums(nums.size());
for (int i = newnums.size() - 1; i >= 0; --i)
{
int a = nums[left] > 0 ? nums[left] : -nums[left];
int b = nums[right] > 0 ? nums[right] : -nums[right];
if (a >= b)
{
newnums[i] = a * a;
++left;
}
else
{
newnums[i] = b * b;
--right;
}
}
return newnums;
}
};

思想

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

此时可以考虑双指针法了,left 指向起始位置,right 指向终止位置。

定义一个新数组newnums,和原数组一样的大小,让 i 指向新数组终止位置。

如果A[left] * A[left] < A[right] * A[right] 那么newnums[i] = A[left] * A[left]; 。反之= A[right] * A[right]

复杂度分析

相比于双层for循环的暴力解法,快慢指针的方法可以让时间复杂度降为O(n)O(n)
空间复杂度O(n)O(n)

并查集

并查集

主要用于解决元素分组的问题。主要操作有集合(或单个元素)的合并查询元素所在的集合
元素以在同一棵树下为标志,认为在同一集合中。多个集合对应着多棵不同的树,组成了森林。
逻辑上是树形结构,实际上用数组存储元素所在集合的根节点。

合并

合并 x 和 y 两个元素时,不能直接合并两个元素,而是要合并两个元素所在树的根节点。

查询

查询 x 和 y 是否在同一个集合,是查询 x 和 y 对应的根节点是否相同。

合并示例

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<iostream>
const int SIZE = 9;
int parent[SIZE];
// 非递归版查询x的根节点
int find(int x)
{
while(x != parent[x])
{
x = parent[x];
}
return x;
}
// 递归版查询x的根节点
int r_find(int x)
{
if(x == parent[x]) return x;
return r_find(parent[x]);
}
// 合并x和y
void merge(int x, int y)
{
int x_root = find(x);
int y_root = find(y);
if (x_root != y_root)
{
parent[y_root] = x_root;
}
}
int main()
{
for(int i = 1; i < SIZE; ++i)
{
parent[i] = i;
}
int x, y;
// 输入6组两个整数,全都合并。
for(int i = 1; i <= 6; ++i)
{
std::cin >> x >> y;
merge(x, y);
}
for(int i = 1; i < SIZE; ++i)
{
std::cout << parent[i] << " ";
}
std::cout << std::endl;
std::cout << "输入要查询的2个元素是否在一个集合:";
std::cin >> x >> y;
std::cout << (find(x) == find(y) ? "在" : "不在") << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
1 3
1 2
5 4
2 4
6 8
8 7
输出parent数组:
1 1 1 5 1 6 6 6
输入要查询的2个元素是否在一个集合:
2 4
输出:

路径压缩