1.题目

2.思路
(1)正负代表方向,正代表向➡️右边走。负数代表向左⬅️走。
(2)绝对值大小代表行星的大小。
(3)遍历每个小行星 a:
1)如果 a > 0:向右走,不会和左边的发生碰撞(先入栈)。
2)如果 a < 0:可能会和栈里"向右走"的发生连续碰撞:
当 栈顶 > 0 且 栈顶的大小 < |a|:栈顶爆炸(pop),继续看下一个栈顶。
如果遇到 栈顶 > 0 且 栈顶的大小 == |a|:两者都爆炸(pop),当前 a 也没了,结束。
如果遇到 栈顶 > 0 且 栈顶的大小 > |a|:当前 a 爆炸,不入栈。
3)如果栈空了或栈顶是负数:说明不会再撞了,a 入栈。
补充:栈空了说明左边已经没有任何活着的小行星了。那 a 向左走,也没人跟它迎面相撞,所以 a 一定能留下来,入栈。
栈顶是负数,表示左边最近的那颗小行星也在向左走。
栈顶 < 0:左边那颗也向左。当前 a < 0:你也向左,同方向永远不会相撞(它们只会一起往左跑,距离不会变小到相撞)。
-,-
时间复杂度 O(n),因为每个元素最多进栈/出栈一次。
flag的定义?
在处理 a < 0(向左)的小行星时,我们会用 while 循环让它和栈顶那些 >0(向右)的小行星连续碰撞。
flag = true:当前 a 还存在,可能还能继续撞,也可能最后留下
flag = false:当前 a 已经爆炸了(或者和栈顶同归于尽),不应该入栈
3.代码实现
java
class Solution {
public int[] asteroidCollision(int[] asteroids) {
//用队列实现栈
Deque<Integer> st=new ArrayDeque<>();
for(int num:asteroids)
{
//num代表当前遍历的小行星
if(num>0)
{
st.push(num);//将正(向右走的)行星都加入到栈中
}else{
// 当前负数小行星是否还存在
boolean flag=true;
while(flag==true&&!st.isEmpty()&&st.peek()>0)
{
int top=st.peek();
int topSize=Math.abs(top);
int numSize=Math.abs(num);
if(topSize>numSize)
{
// 当前小行星爆炸
flag=false;
}else if(topSize==numSize)
{
// 两个都爆炸
st.pop();
flag=false;
}else{
// 栈顶爆炸
st.pop();
}
}
if(flag==true)
{
st.push(num);
}
}
//如果当前小行星 a 在碰撞过程中没有被炸掉(还"活着"),就把它放进栈里,表示它最终留下来。
}
int m=st.size();
int[] res=new int[m];
// stack 是从右到左存的(push在栈顶),需要反向输出
for(int i=res.length-1;i>=0;i--)
{
res[i]=st.pop();
}
return res;
}
}