前言
leetcode 每周末都会举行编程比赛,一共四道题,虽然都有参加,但是水平依然有限,名词并不是很好。不过参加比赛的一个好处就是可以在比赛后review别人的解答,这是一个非常棒的学习材料,因为可以从别人的解答里发现高手的脑回路。因此这里挑选别人的解题代码进行讲解、归纳而不是我自己的答案,希望这归纳也能给大家带来启发!
leetcode 945. Minimum Increment to Make Array Unique
题目
Given an array of integers A, a move consists of choosing any A[i], and incrementing it by 1.
Return the least number of moves to make every value in A unique.
Example 1:
Input: [1,2,2]
Output: 1
Explanation: After 1 move, the array could be [1, 2, 3].
Example 2:
Input: [3,2,1,2,1,7]
Output: 6
Explanation: After 6 moves, the array could be [3, 4, 1, 2, 5, 7].
It can be shown with 5 or less moves that it is impossible for the array to have all unique values.
Note:
0 <= A.length <= 40000
0 <= A[i] < 40000
思路
给出A数组中的数字并不是唯一的,每次对这些数字只能加一,统计最小的加一的次数。可以使用贪心算法进行求解,对A数组进行从小到大的排序使得A[i+1]>=A[i],遇到重复的数字(A[i+1] == A[i])之后,便在当前的数字基础上加一(A[i+1]++),即,使得A[i+1] = A[i] + 1即可,刚刚好满足题目最小的要求。以此类推再遍历数组A一遍即可。
他山之石,可以攻玉
// using c++
//Ref:@neal_wu
class Solution {
public:
int minIncrementForUnique(vector<int>& A) {
sort(A.begin(), A.end());
int lowest = -1, total = 0;
for (int a : A) {
lowest = max(lowest, a);
total += lowest - a;
lowest++;
}
return total;
}
};
Note:使用c++进行遍历的时候,c++11的新特性可以使遍历的代码更加简单
leetcode 946. Validate Stack Sequences
题目
Given two sequences pushed and popped with distinct values, return true if and only if this could have been the result of a sequence of push and pop operations on an initially empty stack.
Example 1:
Input: pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
Output: true
Explanation: We might do the following sequence:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
Example 2:
Input: pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
Output: false
Explanation: 1 cannot be popped before 2.
Note:
0 <= pushed.length == popped.length <= 1000
0 <= pushed[i], popped[i] < 1000
pushed is a permutation of popped.
pushed and popped have distinct values.
思路
题目要求模拟一个栈的运行,最简单的方法就是使用库中的stack进行模拟运行来判断,因此只要定义好出错条件即可。
- 每压入一个pushed元素,将当前栈顶元素与puped数组元素比较
- 如果相等,弹出栈顶元素
- 继续遍历、压入pushed元素
- 如果遍历结束pushed元素,pushed和poped数组都为空,则表示符合栈的要求。其他情况均返回false。
他山之石,可以攻玉
// using c++
//Ref:@user0947c
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack < int > s;
int j = 0;
for (int i = 0; i < pushed.size(); i++) {
s.push(pushed[i]);
while (!s.empty() && j < popped.size() && s.top() == popped[j]) {
s.pop();
j++;
}
}
return s.empty() && j == popped.size();
}
};
leetcode 947. Most Stones Removed with Same Row or Column
题目
On a 2D plane, we place stones at some integer coordinate points. Each coordinate point may have at most one stone.
Now, a move consists of removing a stone that shares a column or row with another stone on the grid.
What is the largest possible number of moves we can make?
Example 1:
Input: stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
Output: 5
Example 2:
Input: stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
Output: 3
Example 3:
Input: stones = [[0,0]]
Output: 0
Note:
1 <= stones.length <= 1000
0 <= stones[i][j] < 10000.
思路
判断这种不相交集合的问题,使用并查集是最方便的解决方法(并查集的基本概念在其他题目中也有使用:LeetCode 721. Accounts Merge)。
这里不同的一点是操作对象变成了平面中的点,相当于增加了维数,因此在初始化并查集数组的时候,注意使用总共(x+y)大小进行初始化即可。
他山之石,可以攻玉
// using c++
//Ref:@awic
class DSU
{
private:
vector<int> parent;
public:
DSU(int n) {
parent.resize(n);
for(int i = 0; i<n; ++i)
parent[i] = i;
};
~DSU() = default;
int find(int x) {
if(parent[x] != x)
parent[x] = find(parent[x]);
return parent[x];
}
void union_(int x, int y) {
parent[find(x)] = find(y);
}
};
class Solution {
public:
int removeStones(vector<vector<int>>& stones)
{
int n = stones.size();
DSU dsu(20000);
for (const auto& stone : stones) {
dsu.union_(stone[0], stone[1]+10000);
}
set<int> seen;
for (const auto& stone : stones) {
seen.insert(dsu.find(stone[0]));
}
return n-seen.size();
}
};
948. Bag of Tokens
题目
You have an initial power P, an initial score of 0 points, and a bag of tokens.
Each token can be used at most once, has a value token[i], and has potentially two ways to use it.
If we have at least token[i] power, we may play the token face up, losing token[i] power, and gaining 1 point.
If we have at least 1 point, we may play the token face down, gaining token[i] power, and losing 1 point.
Return the largest number of points we can have after playing any number of tokens.
Example 1:
Input: tokens = [100], P = 50
Output: 0
Example 2:
Input: tokens = [100,200], P = 150
Output: 1
Example 3:
Input: tokens = [100,200,300,400], P = 200
Output: 2
tokens.length <= 1000
0 <= tokens[i] < 10000
0 <= P < 10000
思路
当时做的时候没有看懂题,纠结了很久,其实题意和解题思路都很简单,和第一题一样使用贪心算法即可。
题目要求返回最多能得到多少分,换言之就是在给定初始能量P的情况下尽可能多翻正面的牌子。
- 按照牌子的能量从小到大进行排序
- 先翻能量小的牌子到正面,翻到翻不动为止,记录当前得分。
- 然后用1个积分翻最大的能量牌子。
- 继续第2, 3个步骤,直到遍历完所有元素或者翻不动正面的牌子且没有足够积分换能量,退出。
注意:因为题解同时从数组的头和尾进行遍历,遍历时相遇的情况一定要仔细判断。
他山之石,可以攻玉
// using c++
//Ref:@user0947c
class Solution {
public:
int bagOfTokensScore(vector<int>& tokens, int P) {
sort(tokens.begin(), tokens.end());
int i = 0, j = tokens.size()-1;
int cur = 0, maxx = 0;
while (i <= j) {
if (tokens[i] <= P) {
cur++;
maxx = max(maxx, cur);
P -= tokens[i];
i++;
}
else if (cur > 0) {
P += tokens[j];
cur--;
j--;
}
else break;
}
return maxx;
}
};