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

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

题目

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

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

分析

下面以一个具体的例子来分析小行星碰撞的规律。先假设有 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. 如果一颗小行星向左飞行,而位于栈顶的小行星向右飞行,那么它将与位于栈顶的小行星相撞。如果位于栈顶的小行星较小,那么它将爆炸消失,也就是说它将出栈。然后判断它是否将与下一颗位于栈顶的小行星相撞。如果小行星与栈中所有小行星相撞之后仍然没有爆炸消失,那么它将入栈

代码实现

class Solution {
public:
    vector asteroidCollision(vector& asteroids) {
        vector 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;
    }
};

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

你可能感兴趣的:(数据结构,c++,开发语言,数据结构)