1. 问题描述:
给定一个整数数组 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 发生
示例 4:
输入:
asteroids = [-2, -1, 1, 2]
输出: [-2, -1, 1, 2]
解释:
-2 和 -1 向左移动,而 1 和 2 向右移动。
由于移动方向相同的行星不会发生碰撞,所以最终没有行星发生碰撞。
说明:
- 数组
asteroids
的长度不超过10000
。 - 每一颗行星的大小都是非零整数,范围是
[-1000, 1000]
。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/asteroid-collision
2. 思路分析:
分析题目可以知道这道题目类似于匹配元素的问题,所以我们可以尝试使用栈来匹配元素从而删除不符合要求的元素,因为涉及到两个方向,而且当向左运动遇到之前向右运动的行星才有可能会发生爆炸,所以对于行星爆炸有以下几种情况:
a:当前遍历的向左运动的行星遇到之前向右运动的行星,当前遍历的行星小于之前向右边运动的行星,当前遍历的行星爆炸
b:当前遍历的向左运动的行星遇到之前向右运动的行星,当前遍历的行星大于之前向右边运行的行星,向右边运动的行星爆炸
c:当前遍历的向左运动的行星遇到之前向右运动的行星,当前遍历的行星等于之前向右边运动的行星,两个行星爆炸
栈中我们存储的是向右运动而且目前不会爆炸的行星,这样我们就就可以使用当前遍历的元素与栈顶元素进行匹配,在匹配的时候弹出栈中遇到当前遍历行星之后会炸裂的行星,例如对于b情况就是需要持续弹出栈中的元素,因为栈中的元素比较小所以会炸裂,并且当两个行星同时炸裂或者是当前遍历的行星炸裂的时候是不能够将当前遍历的元素加入到栈中的,因为这个时候行星都炸裂了,其余的情况说明是在遍历的时候栈中的元素最后会全部炸裂,我们可以在遍历过程中添加一个标志来区分行星炸裂的不同情况
3. 代码如下:
from typing import List
class Solution:
def asteroidCollision(self, asteroids: List[int]) -> List[int]:
stack = list()
for i in range(len(asteroids)):
cur = asteroids[i]
# 设置一个标志来检测是否能够向栈中添加元素
f = 0
while stack and cur < 0 < stack[-1]:
if stack[-1] < -cur:
# 栈中之前的元素会炸裂, 然后继续循环
stack.pop()
# 相等的时候栈顶元素与当前遍历的元素都会炸裂
elif stack[-1] == -cur:
stack.pop()
f = 1
break
# 栈顶元素大于当前遍历的元素那么当前遍历的元素会炸裂
else:
f = 1
break
# 当存在以下两种情况的时候是不能够往栈中添加元素的: 第一个是两个元素相等, 第二个是栈顶元素大于当前遍历的元素
if not f: stack.append(cur)
return stack