《剑指 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;
    }
};

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

相关推荐
未来可期LJ31 分钟前
【C++ 设计模式】单例模式的两种懒汉式和饿汉式
c++·单例模式·设计模式
Trouvaille ~1 小时前
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
c++·c++20·编译原理·编译器·类和对象·rvo·nrvo
little redcap1 小时前
第十九次CCF计算机软件能力认证-乔乔和牛牛逛超市
数据结构·c++·算法
AI原吾2 小时前
掌握Python-uinput:打造你的输入设备控制大师
开发语言·python·apython-uinput
机器视觉知识推荐、就业指导2 小时前
Qt/C++事件过滤器与控件响应重写的使用、场景的不同
开发语言·数据库·c++·qt
毕设木哥2 小时前
25届计算机专业毕设选题推荐-基于python的二手电子设备交易平台【源码+文档+讲解】
开发语言·python·计算机·django·毕业设计·课程设计·毕设
珞瑜·2 小时前
Matlab R2024B软件安装教程
开发语言·matlab
weixin_455446172 小时前
Python学习的主要知识框架
开发语言·python·学习
孤寂大仙v2 小时前
【C++】STL----list常见用法
开发语言·c++·list
她似晚风般温柔7893 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app