《剑指 Offer》专项突破版 - 面试题 37 : 小行星碰撞(C++ 实现)

题目链接LCR 037. 行星碰撞 - 力扣(LeetCode)

题目

输入一个表示小行星的数组,数组中每个数字的绝对值表示小行星的大小,数字的正负号表示小行星运动的方向,正号表示向右飞行,负号表示向左飞行。如果两颗小行星相撞,那么体积较小的小行星将会爆炸最终消失,体积较大的小行星不受影响。如果相撞的两颗小行星大小相同,那么它们都会爆炸消失。飞行方向相同的小行星永远不会相撞(因为每一颗小行星以相同的速度移动)。求最终剩下的小行星。例如,有 6 颗小行星 4, 5, -6, 4, 8, -5,如下图所示(箭头表示飞行的方向),它们相撞之后最终剩下 3 颗小行星 -6, 4, 8

分析

下面以一个具体的例子来分析小行星碰撞的规律。先假设有 6 颗小行星 4, 5, -6, 4, 8, -5,然后逐一分析它们的飞行情况。第 1 颗是向右飞行的大小为 4 的小行星,此时还不知道它会不会和其他小行星碰撞,可以先将它保存到某个数据容器中。第 2 颗还是一颗向右飞行的小行星,它的大小为 5,它和前面一颗小行星的飞行方向相同,所以不会碰撞。但现在还不知道它会不会和后面的小行星碰撞,因此也将它保存到数据容器中。第 3 颗是一颗向左飞行的小行星,大小为 6,由于它和前面两颗小行星是相向而行的,因此会和前面两颗小行星相撞 。先后向数据容器中保存了大小为 4、5 的两颗小行星,后保存到数据容器中的小行星先和其他的小行星相撞,这符合 "后进先出" 的顺序,所以可以考虑用来实现这个数据容器。

根据题目的碰撞规则,小的小行星将会爆炸消失,因此当大小分别为 5 和 6 的两颗小行星相撞时,大小为 5 的小行星会爆炸消失。大小为 6 的小行星继续向左飞行,它将和大小为 4 的小行星相撞。大小为 4 的小行星爆炸消失,留下大小为 6 的小行星向左飞行。此时左边已经没有更多的小行星和这颗大小为 6 的小行星相撞,将它入栈。

接下来是两颗向右飞行的小行星,大小分别为 4 和 8,它们和大小为 6 的小行星背向飞行,肯定不会相撞,因此将它们也先后入栈。最后是一颗大小为 5 向左飞行的小行星,此时栈中保存了 3 颗小行星 -6, 4, 8,大小为 8 的小行星离它最近而且相向飞行,因此它将与大小为 8 的小行星相撞,然后爆炸消失。最终剩下 3 颗小行星 -6, 4, 8

上述分析过程可以用下表来总结:

步骤 小行星 操作 注释
1 4 入栈 4
2 5 入栈 4, 5
3 -6 相撞 -6 -6、5 相撞,5 出栈;-6、4 相撞,4 出栈;-6 入栈
4 4 入栈 -6, 4
5 8 入栈 -6, 4, 8
6 -5 相撞 -6, 4, 8 -5、8 相撞

由此可以总结出小行星相撞的规律:

  1. 如果一颗小行星向右飞行,那么它一定不会和前面的小行星相撞,可以直接将它入栈

  2. 如果一颗小行星向左飞行,而位于栈顶的小行星向右飞行,那么它将与位于栈顶的小行星相撞。如果位于栈顶的小行星较小,那么它将爆炸消失,也就是说它将出栈。然后判断它是否将与下一颗位于栈顶的小行星相撞。如果小行星与栈中所有小行星相撞之后仍然没有爆炸消失,那么它将入栈

代码实现

cpp 复制代码
class Solution {
public:
    vector<int> asteroidCollision(vector<int>& asteroids) {
        vector<int> result;  // 用数组模拟栈
        for (int as : asteroids)
        {
            if (as > 0)
            {
                result.push_back(as);
            }
            else  // as < 0
            {
                while (!result.empty() && result.back() > 0 && result.back() < -as)
                {
                    result.pop_back();
                }

                if (!result.empty() && result.back() == -as)
                {
                    result.pop_back();
                }
                else if (result.empty() || result.back() < 0)
                {
                    result.push_back(as);
                }
            }
        }
        return result;
    }
};

栈中保存的小行星彼此都不会相撞。如果栈中既有向左飞行的小行星也有向右飞行的小行星,那么所有向左飞行的小行星都位于向右飞行的小行星的左边,也就是说,栈中所有负数都位于正数的左边

相关推荐
黑马程序员毕设31 分钟前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
心抵鹊1 小时前
归并排序之翻转对(hard)
数据结构·算法
_Twink1e1 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen
问天_观心1 小时前
大模型微调学习(一)
开发语言·人工智能·学习·语言模型·github
阿里嘎多学长1 小时前
2026-09-03 GitHub 热点项目精选
开发语言·程序员·github·代码托管
dong_junshuai2 小时前
每天一个开源项目#87 fmt:24.5K Stars 的 C++ 格式化核心
c++·开源·github
源代码•宸2 小时前
前置准备:定时微服务背景和现状
开发语言·经验分享·后端·微服务·云原生·架构·golang
2601_967338712 小时前
C#上位机开发零基础入门到精通全套视频
开发语言·c#
雪的季节3 小时前
Multisim14.0的详细中文安装步骤【附安装包】
c++
小白学大数据3 小时前
超简单:用 Python 让 Excel 飞起来:用 openpyxl 把重复报表整理交给脚本
开发语言·数据库·python·excel