题目描述
给定一个整数数组 a s t e r o i d s asteroids asteroids,表示在同一行的行星。
对于数组中的每一个元素,其绝对值表示行星的大小,正负表示行星的移动方向(正表示向右移动,负表示向左移动)。每一颗行星以相同的速度移动。
找出碰撞后剩下的所有行星。碰撞规则:两个行星相互碰撞,较小的行星会爆炸。如果两颗行星大小相同,则两颗行星都会爆炸。两颗移动方向相同的行星,永远不会发生碰撞。
示例 1:
输入:asteroids = [5,10,-5]
输出:[5,10]
解释:10 和 -5 碰撞后只剩下 10 。 5 和 10 永远不会发生碰撞。
示例 2:
输入:asteroids = [8,-8]
输出:[]
解释:8 和 -8 碰撞后,两者都发生爆炸。
示例 3:
输入:asteroids = [10,2,-5]
输出:[10]
解释:2 和 -5 发生碰撞后剩下 -5 。10 和 -5 发生碰撞后剩下 10 。
提示:
- 2 < = a s t e r o i d s . l e n g t h < = 1 0 4 2 <= asteroids.length <= 10^{4} 2<=asteroids.length<=104
- − 1000 < = a s t e r o i d s [ i ] < = 1000 -1000 <= asteroids[i] <= 1000 −1000<=asteroids[i]<=1000
- a s t e r o i d s [ i ] ! = 0 asteroids[i] != 0 asteroids[i]!=0
思路
1.遍历输入数组,如果栈为空,直接将当前元素压入栈里。如果栈非空,则进行判断。
栈非空,则栈顶的元素和输入元素分别为两个行星。栈顶元素是左边的行星,输入元素是右边的行星。
2.判断两个行星的运动方向
如果两个行星同方向,或者左边的行星向左,右边的行星向右,两颗行星就不会发生碰撞,直接将右行星入栈。
如果不是以上的情况,两个行星一定会发生碰撞。
一定会发生碰撞的情况:
1.左边行星绝对值 > 右边行星绝对值
右行星爆炸,所以左行星不出栈,右行星不入栈,进入下一轮循环。
2.左边行星绝对值 == 右边行星绝对值
两个行星都爆炸,左行星出栈,右行星不入栈,进入下一轮循环。
3.左边行星绝对值 < 右边行星绝对值
左行星爆炸,所以左行星出栈,而右行星不可以入栈,还需要判断左边是否还有冲突的行星,所以需要再次进行判断。
代码中我使用了i–,进入新的循环,但执行了i–之后输入元素还是上一轮的元素,所以可以实现再次判断。
循环结束后所有元素出栈到返回数组中。
C++ 代码
class Solution {
public:
vector<int> asteroidCollision(vector<int>& asteroids) {
// 定义栈
stack<int> s;
// 返回数组
vector<int> ret;
// 遍历输入数组
for (int i = 0; i < asteroids.size(); i++)
{
// 栈非空
if (!s.empty())
{
// 栈顶元素和输入元素同方向 或者 栈顶元素向左输入元素向右 输入元素入栈
if ((s.top() < 0 && asteroids[i] < 0) || (s.top() > 0 && asteroids[i] > 0)
|| (s.top() < 0 && asteroids[i] > 0))
s.push(asteroids[i]);
// 栈顶元素向右 输入元素向左 会产生碰撞
else
{
// a为栈顶元素绝对值 b为输入元素绝对值
int a = abs(s.top()), b = abs(asteroids[i]);
// a > b 栈顶元素绝对值更大 输入元素爆炸 进入下一轮循环
// a == b 栈顶元素和输入元素绝对值相等 两个元素都爆炸
// a < b 栈顶元素爆炸 输入元素继续循环判断
if (a > b) continue;
else if (a == b) { s.pop(); continue; }
else if (a < b) { s.pop(); i--; }
}
}
// 栈为空就直接push入栈
else s.push(asteroids[i]);
}
// 栈非空 存入返回数组
while (!s.empty())
{
ret.push_back(s.top());
s.pop();
}
// 返回数组倒序
reverse(ret.begin(), ret.end());
return ret;
}
};