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

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

相关推荐
yeziyfx2 分钟前
kotlin中集合的用法
android·开发语言·kotlin
祁思妙想4 分钟前
【LeetCode100】--- 1.两数之和【复习回滚】
数据结构·算法·leetcode
小鲈鱼-9 分钟前
【LeetCode4.寻找两个正序数组的中位数】二分O(log(m+n))
c++·算法
橘颂TA11 分钟前
【C++】红黑树的底层思想 and 大厂面试常问
数据结构·c++·算法·红黑树
三体世界1 小时前
TCP传输控制层协议深入理解
linux·服务器·开发语言·网络·c++·网络协议·tcp/ip
你的冰西瓜1 小时前
C++ 中最短路算法的详细介绍
c++·算法·图论·最短路
随心点儿1 小时前
使用python 将多个docx文件合并为一个word
开发语言·python·多个word合并为一个
不学无术の码农1 小时前
《Effective Python》第十三章 测试与调试——使用 Mock 测试具有复杂依赖的代码
开发语言·python
tomcsdn311 小时前
SMTPman,smtp的端口号是多少全面解析配置
服务器·开发语言·php·smtp·邮件营销·域名邮箱·邮件服务器
<但凡.1 小时前
数据结构与算法之美:广义表
数据结构·c++·算法