735 行星碰撞——Leetcode天天刷【栈】(2022.7.13)
前言
虽然是黄色,中等题目,但我还是觉得简单,不过需要注意一些细节。
题目信息
简单描述一下题目:就是一个数组,元素表示行星的质量和移动方向,负值表示向左移动,正值表示向右移动,行星碰撞时,如果质量相同则都会消失,否则留下质量较大的。
输入与输出
和之前的一样,为了方便在本地测试,所以在输入与输出的设置做了处理。
输入
我们对测试用例的数量不做限制,对每个测试用例:
第一行输入整数n,表示行星的数量,也就是数组的尺寸。
第二行输入n个整数,表示行星的质量和行星移动的方向。
输出
每个测试用例输出一行,输出碰撞后剩下的行星,如果没有行星,则不用输出。
测试用例
输入用例
3
5 10 -5
2
8 -8
3
10 2 -5
4
-2 -1 1 2
4
-2 -2 1 -2
输出用例
5 10
10
-2 -1 1 2
-2 -2 -2
提示
2 <= asteroids.length <= 104
-1000 <= asteroids[i] <= 1000
asteroids[i] != 0
法一:栈
看题目的描述,首先我们需要对题目先分析,我们在遍历行星的时候,行星在数组的索引,其实可以认为是初始位置,行星碰撞的条件在于相向运动,且还有一个隐藏条件是两个行星的初始位置的关系和移动方向相反。
情况如下
结合上面的分析,我们可以得出基于 栈
的解题思路。
我们可以在遍历行星的时候,如果当前行星 “未碰撞”,注意这里指的是未碰撞,即在后面还是有可能会碰撞。所以我们可以先将行星存储起来,对于当前行星,我们显然需要将其和栈顶的行星判断是否会碰撞,如果会碰撞,我们显然需要判断碰撞后会留下哪颗行星。反映到程序其实就是出栈和压栈。
那么,我们就将入栈的条件来列举:
- 栈空。
- 栈的顶部为负值,表示栈顶的行星是向左运动,那么无论当前行星向哪个方向移动,都不会和前面的发生碰撞。
- 当前行星为正值,表示向右运动,同2,不会和前面的行星碰撞。
这上面其实就是当前行星不会和前面的行星发生碰撞的情况,如果发生碰撞,我们需要处理。
可以知道,此时栈顶为正值,当前行星为负值,我们需要比较绝对值,如果栈顶小于当前行星,需要出栈,直到栈空或者不会碰撞,或者碰撞后当前行星消失。如果等于,还需要出栈,行星消失,如果大于,行星消失。到这里,如果行星还没消失,那就可以入栈了。
时间复杂度:O(n)。
空间复杂度:O(n)。
通过截图。
Code(C++)
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
class Solution
{
public:
/// <summary>
/// 栈
/// 遍历数组,当栈空或者当前元素和栈符号相同时,压栈
/// 特殊情况,由于方向,所以当栈顶为负值时,也可以压栈
/// 否则判断是否需要出栈
/// 完事后,在输出到数组中即可
/// </summary>
/// <param name="asteroids"></param>
/// <returns></returns>
vector<int> asteroidCollision(vector<int>& asteroids)
{
stack<int> stk; // 堆栈存储最终留下的行星
// 遍历行星,判断行星堆栈和出栈
for (int asteroid : asteroids)
{
// 栈空或者不会碰撞
if (stk.empty() || stk.top() < 0 || asteroid > 0)
{
stk.push(asteroid);
}
// 发生碰撞
else
{
// 很明显,碰撞时,栈顶一定是朝右,正值,当前行星一定是朝左,负值
// 碰撞时需要根据质量判断出栈,写一个循环
while (!stk.empty() && stk.top() > 0 && stk.top() < -asteroid)
{
stk.pop();
}
// 栈还有行星的情况下,需要判断是否相等
if (!stk.empty() && stk.top() > 0 && stk.top() == -asteroid)
{
stk.pop();
}
// 栈空了,或者此时同向
else if (stk.empty() || stk.top() < 0)
{
stk.push(asteroid);
}
}
}
int n = stk.size(); // 获取最终答案的数组尺寸
vector<int> ans(n);
// 逆序存储
for (int i = n - 1; i >= 0; --i)
{
ans[i] = stk.top();
stk.pop();
}
return ans;
}
};
int main(int argc, char** argv)
{
int n;
Solution sol;
while(cin >> n)
{
vector<int> asteroids(n);
for (int& ast : asteroids)
{
cin >> ast;
}
auto ans = sol.asteroidCollision(asteroids);
int n1 = ans.size();
if (n1 == 0)
{
continue;
}
for (int i = 0; i < n1 - 1; ++i)
{
cout << ans[i] << ' ';
}
cout << ans[n1 - 1] << endl;
}
return 0;
}
后话
额,今天就没有一题多解了,本来想过双指针,但是却发现并不是很适合,所以就这样了。