Asteroid Collision
Stack — push each asteroid; on a right-moving stack top vs left-moving incoming, pop the smaller (or both if equal).
Problem#
Positive integers move right, negatives move left, all at the same speed. On collision, the smaller (by absolute value) explodes; equal sizes destroy each other. Return the surviving asteroids.
Examples#
[5,10,-5]→[5,10].[8,-8]→[];[10,2,-5]→[10].
Constraints#
2 <= asteroids.length <= 10^4.
Approach#
Stack of survivors. For each new asteroid, while it’s negative and the stack top is positive: if |top| < |new|, pop and continue; if equal, pop and discard the new one; if |top| > |new|, discard the new one. Else push.
Solution#
class Solution {public: vector<int> asteroidCollision(vector<int>& a) { vector<int> st; for (int x : a) { bool alive = true; while (alive && x < 0 && !st.empty() && st.back() > 0) { if (st.back() < -x) st.pop_back(); else if (st.back() == -x) { st.pop_back(); alive = false; } else alive = false; } if (alive) st.push_back(x); } return st; }};func asteroidCollision(a []int) []int { st := []int{} for _, x := range a { alive := true for alive && x < 0 && len(st) > 0 && st[len(st)-1] > 0 { top := st[len(st)-1] if top < -x { st = st[:len(st)-1] } else if top == -x { st = st[:len(st)-1] alive = false } else { alive = false } } if alive { st = append(st, x) } } return st}from typing import List
class Solution: def asteroidCollision(self, asteroids: List[int]) -> List[int]: st: List[int] = [] for x in asteroids: alive = True while alive and x < 0 and st and st[-1] > 0: top = st[-1] if top < -x: st.pop() elif top == -x: st.pop() alive = False else: alive = False if alive: st.append(x) return stvar asteroidCollision = function(asteroids) { const st = []; for (const x of asteroids) { let alive = true; while (alive && x < 0 && st.length > 0 && st[st.length - 1] > 0) { const top = st[st.length - 1]; if (top < -x) st.pop(); else if (top === -x) { st.pop(); alive = false; } else alive = false; } if (alive) st.push(x); } return st;};class Solution { public int[] asteroidCollision(int[] asteroids) { Deque<Integer> st = new ArrayDeque<>(); for (int x : asteroids) { boolean alive = true; while (alive && x < 0 && !st.isEmpty() && st.peek() > 0) { int top = st.peek(); if (top < -x) st.pop(); else if (top == -x) { st.pop(); alive = false; } else alive = false; } if (alive) st.push(x); } int[] out = new int[st.size()]; for (int i = out.length - 1; i >= 0; i--) out[i] = st.pop(); return out; }}function asteroidCollision(asteroids: number[]): number[] { const st: number[] = []; for (const x of asteroids) { let alive = true; while (alive && x < 0 && st.length > 0 && st[st.length - 1] > 0) { const top = st[st.length - 1]; if (top < -x) st.pop(); else if (top === -x) { st.pop(); alive = false; } else alive = false; } if (alive) st.push(x); } return st;}Editorial#
The only collision occurs when a leftward asteroid meets a rightward survivor on the stack. The stack invariant — “right-movers followed by left-movers” — means once a left-mover is appended, it never collides again. Each asteroid is pushed at most once and popped at most once.
Complexity#
- Time:
O(n). - Space:
O(n).
Concept revision#
Related#