
Problem Statement
In this problem, we are given an array asteroids
, where each element contains an integer. These integers represent asteroids arranged in a sequence where each index corresponds to their relative position in space. The magnitude of each integer denotes the size of the asteroid, while its sign indicates the direction of its movement; positive values indicate movement to the right, and negative values to the left. All asteroids progress at the same uniform speed.
The primary goal is to deduce the final formation of these asteroids once all collisions have been resolved. Collision behavior is defined as follows: when two asteroids collide, the one with the smaller size is destroyed; if they are of equal size, both are destroyed. Asteroids moving in the same direction do not collide, facilitating a need to focus solely on opposing-direction interactions.
Examples
Example 1
Input:
asteroids = [5,10,-5]
Output:
[5,10]
Explanation:
The 10 and -5 collide resulting in 10. The 5 and 10 never collide.
Example 2
Input:
asteroids = [8,-8]
Output:
[]
Explanation:
The 8 and -8 collide exploding each other.
Example 3
Input:
asteroids = [10,2,-5]
Output:
[10]
Explanation:
The 2 and -5 collide resulting in -5. The 10 and -5 collide resulting in 10.
Constraints
2 <= asteroids.length <= 104
-1000 <= asteroids[i] <= 1000
asteroids[i] != 0
Approach and Intuition
To tackle this problem, the main challenge is to simulate the interactions correctly, considering directional movement and collision outcomes. Let's breakdown how the behavior of such a simulation may unfold using the examples:
Handling Directional Movement:
- If an asteroid moves right and no other asteroid is encountered moving left, it continues its course unhindered.
- Conversely, an asteroid moving left continues unless it encounters an asteroid moving right.
Collision Scenarios:
- Two asteroids moving towards one another will always collide. The result of this collision depends on their sizes:
- If one is larger, the smaller asteroid is destroyed.
- If both are of equal size, both are destroyed.
- Two asteroids moving towards one another will always collide. The result of this collision depends on their sizes:
Let’s expand this using provided examples:
- Example 1:
asteroids = [5, 10, -5]
- Asteroid 10 (moving right) encounters asteroid -5 (moving left). Since 10 is larger, -5 is destroyed, resulting in asteroids [5,10].
- Example 2:
asteroids = [8, -8]
- Here, both asteroids have equal size but opposite directions. Thus, both asteroids are destroyed, resulting in an empty array
[]
.
- Here, both asteroids have equal size but opposite directions. Thus, both asteroids are destroyed, resulting in an empty array
- Example 3:
asteroids = [10, 2, -5]
- Asteroid 2 (moving right) encounters -5 (moving left). Given -5 is larger, asteroid 2 gets destroyed. Then, 10 and -5 (now remaining) collide, and since 10 is larger, -5 is destroyed. We are left with
[10]
.
- Asteroid 2 (moving right) encounters -5 (moving left). Given -5 is larger, asteroid 2 gets destroyed. Then, 10 and -5 (now remaining) collide, and since 10 is larger, -5 is destroyed. We are left with
Logical Implementation:
- A typical solution can utilize a stack data structure:
- Traverse the list of asteroids.
- Use the stack to keep track and manage surviving asteroids.
- For each asteroid, check if a collision occurs (i.e., a right-moving asteroid on the stack and a current left-moving asteroid).
- Resolve collisions per the rules and update the stack accordingly.
The last step includes extracting the status of the stack once all elements are processed, which represents the state of asteroids post all collisions.
Solutions
- C++
- Java
class Solution {
public:
vector<int> asteroidCollision(vector<int>& asts) {
stack<int> asteroidsStack;
for (int ast : asts) {
bool pushToStack = true;
while (!asteroidsStack.empty() && asteroidsStack.top() > 0 && ast < 0) {
if (abs(asteroidsStack.top()) < abs(ast)) {
asteroidsStack.pop();
continue;
} else if (abs(asteroidsStack.top()) == abs(ast)) {
asteroidsStack.pop();
}
pushToStack = false;
break;
}
if (pushToStack) {
asteroidsStack.push(ast);
}
}
vector<int> resultAsteroids(asteroidsStack.size());
for (int i = resultAsteroids.size() - 1; i >= 0; i--) {
resultAsteroids[i] = asteroidsStack.top();
asteroidsStack.pop();
}
return resultAsteroids;
}
};
The provided C++ solution tackles the problem of simulating asteroid collision. The primary data structure used is a stack (asteroidsStack
) to store the asteroids' positions as the algorithm iterates through them. Here's a concise overview of how the solution works:
- Iterate through each asteroid in the provided vector (
asts
). - Use a
while
loop to handle collisions:- If the top of the stack is a right-moving asteroid (positive integer) and the current asteroid is moving left (negative integer), a collision might occur.
- Determine the result of the collision based on size:
- If the asteroid inside the stack is smaller, it gets popped off the stack (destroyed).
- If both asteroids are of the same size, both are destroyed and thus removed.
- If none of the above, the loop breaks as no further collisions for the current asteroid are possible with previous ones.
- After checking collisions, decide if the current asteroid survives and should be pushed onto the stack.
- Finally, transfer the contents of the stack to a results vector (
resultAsteroids
) in correct order.
This solution efficiently handles the collision logic using conditional checks and a stack-based approach, ensuring that each asteroid is processed considering previous ones in O(n) time, with n
being the number of asteroids.
class Solution {
public int[] processAsteroids(int[] spaceRocks) {
Stack<Integer> rockStack = new Stack<Integer>();
for (int rock : spaceRocks) {
boolean shouldAdd = true;
while (!rockStack.isEmpty() && (rockStack.peek() > 0 && rock < 0)) {
if (Math.abs(rockStack.peek()) < Math.abs(rock)) {
rockStack.pop();
continue;
} else if (Math.abs(rockStack.peek()) == Math.abs(rock)) {
rockStack.pop();
}
shouldAdd = false;
break;
}
if (shouldAdd) {
rockStack.push(rock);
}
}
int[] finalRocks = new int[rockStack.size()];
for (int i = finalRocks.length - 1; i >= 0; i--) {
finalRocks[i] = rockStack.pop();
}
return finalRocks;
}
}
The Java solution provided simulates the collision of asteroids where each entry in the input array represents asteroid direction and size. Positive values represent an asteroid moving right, while negative values signify movement to the left. Here's an essential breakdown of the implementation approach:
- Initialize a
Stack<Integer>
to handle the processing of asteroids dynamically. - Loop through each asteroid in the input array:
- Set a flag
shouldAdd
to determine if the current asteroid survives and therefore should be added to the stack. - Process potential collisions:
- While the stack is not empty and the current asteroid is moving left (negative) against the right-moving (positive) asteroid at the top of the stack, check for collisions:
- If the absolute size of the asteroid at the top of the stack is less than the current asteroid, pop the stack since the top asteroid is destroyed.
- If both asteroids are of equal size, pop the top asteroid and set
shouldAdd
to false, as both asteroids destroy each other.
- While the stack is not empty and the current asteroid is moving left (negative) against the right-moving (positive) asteroid at the top of the stack, check for collisions:
- After processing the collisions, push the current asteroid onto the stack if it survives (
shouldAdd
is true).
- Set a flag
- Convert the stack to an array in reverse order to maintain the correct sequence, as the stack reverses the order during processing.
This approach efficiently resolves the asteroid collisions, ensuring that only asteroids that survive all collisions are included in the result. The stack is particularly useful here for its ability to process elements in LIFO order, matching the problem's requirement where only the most recent moving-right asteroid can collide with a newly encountered moving-left asteroid.
No comments yet.