文章目录
- 0. Leetcode [977. 有序数组的平方](https://leetcode-cn.com/problems/squares-of-a-sorted-array/)
- 1. Leetcode [268. 丢失的数字](https://leetcode-cn.com/problems/missing-number/)
- 3. Leetcode [1877. 数组中最大数对和的最小值](https://leetcode-cn.com/problems/minimize-maximum-pair-sum-in-array/)
- 4. Leetcode [950. 按递增顺序显示卡牌](https://leetcode.cn/problems/reveal-cards-in-increasing-order/)
0. Leetcode 977. 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
提示:
1 ≤ n u m s . l e n g t h ≤ 104 1 \le nums.length \le104 1≤nums.length≤104
− 104 ≤ n u m s [ i ] ≤ 104 -104 \le nums[i] \le 104 −104≤nums[i]≤104
nums 已按 非递减顺序 排序
分析与解答
对于本题可以先计算出 nums 的平方数,再排序:
class Solution {
public:
void qSort(vector<int>& nums, int low, int high) { // 排序
if (low >= high) {
return;
}
int pivot = nums[low];
int l(low), r(high);
while (l < r) {
while (nums[r] > pivot) {
r--;
}
if (l < r) {
nums[l] = nums[r];
}
while (nums[l] <= pivot && l < r) {
l++;
}
if (l < r) {
nums[r] = nums[l];
}
}
nums[l] = pivot;
qSort(nums, low, l - 1);
qSort(nums, l + 1, high);
}
vector<int> sortedSquares(vector<int>& nums) {
vector<int> result;
result.reserve(nums.size());
for (int i = 0; i < nums.size(); ++i) { // 计算平方数后放入数组
result.push_back(nums[i] * nums[i]);
}
qSort(result, 0, result.size() - 1); // 数组排序
return result;
}
};
算法时间复杂度为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)
由于数组为有序数组,因此可以使用双指针方法,找到分界点后依序计算平方数并放入结果数组中。
1. Leetcode 268. 丢失的数字
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
分析与解答
本题可以使用位运算的特性:a ^ a ^ b = 0
,找缺失数字时,可以将数组与 0-n
的所有数字进行异或运算,相当于使用出现的数字与自己做了异或运算,得到 0
,此时最后结果即缺失的数字只出现一次:
class Solution {
public:
int missingNumber(vector<int>& nums) {
int k = 0;
int result(0);
for (int i = 0; i < nums.size(); ++i) {
result = result ^ nums[i] ^ k++;
}
result = result ^ k;
return result;
}
};
由于该方法遍历一次数组,因此算法时间复杂度为 O ( N ) O(N) O(N)
3. Leetcode 1877. 数组中最大数对和的最小值
一个数对 (a,b) 的 数对和 等于 a + b 。最大数对和 是一个数对数组中最大的 数对和 。
比方说,如果我们有数对 (1,5) ,(2,3) 和 (4,4),最大数对和 为 max(1+5, 2+3, 4+4) = max(6, 5, 8) = 8 。
给你一个长度为 偶数 n 的数组 nums ,请你将 nums 中的元素分成 n / 2 个数对,使得:
nums 中每个元素 恰好 在 一个 数对中,且
最大数对和 的值 最小 。
请你在最优数对划分的方案下,返回最小的 最大数对和 。
提示:
n = = n u m s . l e n g t h n == nums.length n==nums.length
2 ≤ n ≤ 105 2 \le n \le 105 2≤n≤105
n 是 偶数 。
1 ≤ n u m s [ i ] ≤ 105 1 \le nums[i] \le 105 1≤nums[i]≤105
分析与解答
本题难点在于贪心算法的理解。对任意四个数字, m i n ≤ x ≤ y ≤ m a x min \le x \le y \le max min≤x≤y≤max,取 ( m i n , m a x ) ; ( x , y ) (min, max);(x, y) (min,max);(x,y) 组合能使最大数对和最小。若取 ( x , m a x ) ; ( m i n , y ) (x, max); (min, y) (x,max);(min,y),此时 x + m a x > m i n + m a x x + max > min + max x+max>min+max 故该组合最大数对和更大;若取 ( y , m a x ) ; ( x , m i n ) (y, max); (x, min) (y,max);(x,min),此时 y + m a x > m i n + m a x y + max > min + max y+max>min+max 故该组合最大数对和更大。因此对有序数组,最大最小两个数匹配为最优数对划分。因此对数组排序后遍历组合即可求出最小的最大数对和:
class Solution {
public:
void qSort(vector<int>& nums, int low, int high) {
if (low >= high) {
return;
}
int pivot = nums[low];
int l(low), r(high);
while (l < r) {
while (nums[r] > pivot) {
r--;
}
if (l < r) {
nums[l] = nums[r];
}
while (nums[l] <= pivot && l < r) {
l++;
}
if (l < r) {
nums[r] = nums[l];
}
}
nums[l] = pivot;
qSort(nums, low, l - 1);
qSort(nums, l + 1, high);
}
int minPairSum(vector<int>& nums) {
// 排序后依次组合最大最小数即可
qSort(nums, 0, nums.size()-1);
int result(-1);
for (int i = 0, j = nums.size() - 1;
i < j; i++, j--) {
if (nums[i] + nums[j] > result) {
result = nums[i] + nums[j];
}
}
return result;
}
};
由于该方法需要排序,因此算法时间复杂度为 O ( N l o g N ) O(NlogN) O(NlogN)
4. Leetcode 950. 按递增顺序显示卡牌
牌组中的每张卡牌都对应有一个唯一的整数。你可以按你想要的顺序对这套卡片进行排序。
最初,这些卡牌在牌组里是正面朝下的(即,未显示状态)。
现在,重复执行以下步骤,直到显示所有卡牌为止:
从牌组顶部抽一张牌,显示它,然后将其从牌组中移出。
如果牌组中仍有牌,则将下一张处于牌组顶部的牌放在牌组的底部。
如果仍有未显示的牌,那么返回步骤 1。否则,停止行动。
返回能以递增顺序显示卡牌的牌组顺序。
答案中的第一张牌被认为处于牌堆顶部。
提示:
1 <= A.length <= 1000
1 <= A[i] <= 10^6
对于所有的 i != j,A[i] != A[j]
分析与解答
!!看懂啦
对长度为 n
的 deck
,假设已有正确排序后的答案数组,此时下标为 0-n
,那么可以按照题意,模拟取出操作时的下标变化。由于取出后数组为升序数组,因此在模拟时,将升序排列后的 deck
依序放入下标数组中第一个元素指示的位置,放入后依题意操作下标数组,直至放完所有数,就构成了答案数组。
class Solution {
public:
vector<int> deckRevealedIncreasing(vector<int>& deck) {
vector<int> result;
result.resize(deck.size());
// 构造下标数组模拟取出顺序
// 排序 deck 后依下标数组顺序放入
deque<int> index(deck.size());
for (int i = 0; i < deck.size(); ++i) { // 这里为下标数组
index[i] = i;
}
sort(deck.begin(), deck.end()); // 排序
for (int i = 0; i < deck.size(); ++i) {
result[index[0]] = deck[i]; // 顺序放入
// 模拟取出顺序
index.pop_front(); // 第一个已经放入
int tmp = index.front(); // 将第一个弹出,放到最后
index.pop_front();
index.push_back(tmp);
}
return result;
}
};