leetCode-735: 行星碰撞

该博客详细介绍了如何使用栈解决行星碰撞的问题。通过创建一个辅助栈,遍历行星数组并判断行星碰撞条件,实现了找出碰撞后剩余行星的功能。关键在于理解符号相反的行星才会碰撞,且较小行星会消失。代码实现清晰,通过实例解释了算法的每一步操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

给定一个整数数组 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 。

解题过程

思路及步骤
(1)创建 Stack 额外空间,方便判断某一元素是否会被碰撞掉;
(2)因为只有符号相反的两个数才有可能发生碰撞,所以我们针对负数来进行判断(建议使用负数);
(3)外层 for 循环遍历原数组;内层 while 循环去判断该元素是否需要入栈,或者被碰撞掉;
(4)还需要一个 flag 标记去识别当前元素是否需要进行入栈;
(5)以负数为例,满足 while 循环的条件是:栈不为空且当前元素为负数;
(6)如果当前元素是负数,且栈顶元素是负数,那么直接 break 掉 while 循环,flag 置为 true,表示当前元素需要入栈,同时也表明符号相同的两个数永远不会发生碰撞;
(7)如果当前元素是负数,并且栈顶元素的绝对值小于当前元素的绝对值,则栈顶元素出栈,表示栈顶元素被碰撞掉了,继续 while 循环,寻找 break 的条件;
(8)如果当前元素是负数,并且栈顶元素的绝对值大于当前元素的绝对值,此时当前元素就会被碰撞掉,那么直接 break 掉 while 循环,flag 置为 false;
(9)如果当前元素为负数,并且栈顶元素的绝对值等于当前元素的绝对值,此时栈顶元素和当前元素都会被碰撞掉,那么在 break 掉 while 循环的同时将 flag 置为 true;
(10)其他情况(栈为空或者当前元素为正数)的话,不满足 while 循环的条件,直接进行入栈操作即可;
(11)将栈中的元素赋值给最终的结果数组即可
注意点:
(1)符号相同的两个数永远不会发生碰撞;
(2)当前元素为负数且当前元素的上一个元素为正数时才会发生碰撞,当前元素为正数且当前元素的上一个元素为负数时不会发生碰撞,这正是我们使用栈来存储数据的优势,同时也是 while 循环为什么使用当前元素为负数来作为判断条件的原因所在
代码展示
public class AsteroidCollision {

    public static int[] asteroidCollision(int[] asteroids) {
        Stack<Integer> tempStack = new Stack<>();
        for (int i = 0; i < asteroids.length; i++) {
            // 是否入栈标识, true-入栈, false-不入栈
            Boolean flag = true;
            // 如果栈不为空且当前元素为负数, 则判断
            while (!tempStack.isEmpty() && asteroids[i] < 0) {
                // 如果当前元素为负数且栈顶元素也为负数, 则 break 掉 while 循环, 当前元素入栈, 进行下一个元素的比较
                // 如果两个数都为负数, 永远也不会发生碰撞
                if (tempStack.peek() < 0) {
                    break;
                }
                // 如果栈顶元素的绝对值小于当前元素的绝对值, 则栈顶元素出栈, 表示栈顶元素已经被碰撞掉
                if (Math.abs(tempStack.peek()) < Math.abs(asteroids[i])) {
                    tempStack.pop();
                } else if (Math.abs(tempStack.peek()) > Math.abs(asteroids[i])) {
                    // 如果栈顶元素的绝对值大于当前元素的绝对值, 则 break 掉 while 循环, 表示当前元素已经被碰撞掉, 进行下一个元素的比较
                    flag = false;
                    break;
                } else {
                    // 如果栈顶元素的绝对值等于当前元素的绝对值, 则栈顶元素出栈, 同时 break 掉 while 循环, 表示栈顶元素和当前元素均被碰撞掉, 进行下一个元素的比较
                    tempStack.pop();
                    flag = false;
                    break;
                }
            }
            // 入栈
            if (flag) {
                tempStack.push(asteroids[i]);
            }
        }
        // 将栈中的元素倒序赋值, 返回
        int[] resultArray = new int[tempStack.size()];
        for (int i = 0; i < resultArray.length; i++) {
            resultArray[resultArray.length - i - 1] = tempStack.pop();
        }
        return resultArray;
    }

    public static void main(String[] args) {
        int[] asteroids = {-2, -1, 1, 2};
        int[] result = asteroidCollision(asteroids);
        for (int i = 0; i < result.length; i++) {
            System.out.printf("%3d", result[i]);
        }
        System.out.println();
    }
    
}
图解示例

int[] asteroids = {-2, -1, 1, 2, -3, 4, 1} 为例:
(1)初始化:
![Alt](https://img-blog.csdnimg.cn/2be76c9cedf54ac7ba7c65069f335ee0.png = x30)
(2)当 i = 0 时,当前元素为 -2,栈为空,不满足 while 循环,所以直接将当前元素 -2 入栈;
![Alt](https://img-blog.csdnimg.cn/1ed55f31ed48450e9f76ae0509953158.png = x30)
(3)当 i = 1 时,当前元素为 -1,栈不为空,满足 while 循环条件,进入 while 循环,栈顶元素为 -2,当前元素与栈顶元素符号相同,永远不会发生碰撞,break 掉 while 循环,将当前元素 -1 入栈;
![Alt](https://img-blog.csdnimg.cn/3e41803efacf4a95908c854b41f0404a.png = x30)
(4)当 i = 2 时,当前元素为 1,栈不为空,不满足 while 循环条件,所以直接将当前元素 1 入栈;
![Alt](https://img-blog.csdnimg.cn/61bdad2db01f42db96226fb3c45913d6.png = x30)
(5)当 i = 3 时,当前元素为 2,栈不为空,不满足 while 循环条件,所以直接将当前元素 2 入栈;
![Alt](https://img-blog.csdnimg.cn/c8043f9aa3d6475ba91646369b45fa69.png = x30)
(6)当 i = 4 时,当前元素为 -3,栈不为空,满足 while 循环条件,进入 while 循环,栈顶元素为 2,当前元素的绝对值大于栈顶元素的绝对值,则将栈顶元素出栈,表示栈顶元素 2 已经被碰撞掉,继续循环,此时栈顶元素为 1,其绝对值仍然小于当前元素的绝对值,则继续出栈,表示栈顶元素 1 也已经被碰撞掉,继续循环,此时栈顶元素为 -1,与当前元素符号相同,永远不会发生碰撞, break 掉 while 循环,同时将当前元素 -3 入栈;
![Alt](https://img-blog.csdnimg.cn/452864c9ee0f4ec2903f80feb3a30a14.png = x30)
(7)当 i = 5 时,当前元素为 4,栈不为空,不满足 while 循环的条件,所以直接将当前元素 4 入栈;这种情况属于:当前元素向右移动,上一个元素向左移动,越来越远,永远不会发生碰撞;
![Alt](https://img-blog.csdnimg.cn/ac330a26f47f472f8bcb95ea29aedd6e.png = x30)
(8)当 i = 6 时,当前元素为 1,栈不为空,不满足 while 循环的条件,所以直接将当前元素 1 入栈;
![Alt](https://img-blog.csdnimg.cn/ee70695059cd4543a01d7a2acef24d6c.png = x30)
(9)所以最终碰撞剩下的元素即为 -2, -1, -3, 4, 1
![Alt](https://img-blog.csdnimg.cn/bafd9504b69b45529531f2a2c795bb36.png = x30)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值