【C/C++】735. 行星碰撞

170 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第23天,点击查看活动详情


题目链接:735. 行星碰撞

题目描述

给定一个整数数组 asteroids,表示在同一行的行星。

对于数组中的每一个元素,其绝对值表示行星的大小,正负表示行星的移动方向(正表示向右移动,负表示向左移动)。每一颗行星以相同的速度移动。

找出碰撞后剩下的所有行星。碰撞规则:两个行星相互碰撞,较小的行星会爆炸。如果两颗行星大小相同,则两颗行星都会爆炸。两颗移动方向相同的行星,永远不会发生碰撞。

提示:

  • 2asteroids.length 1042 \leqslant asteroids.length \leqslant 10^4
  • 1000asteroids[i]1000-1000 \leqslant asteroids[i] \leqslant 1000
  • asteroids[i] != 0

示例 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 。

整理题意

题目给定一个一维整数数组 asteroids,其中每个元素表示一个行星的大小和运动方向:

  • 符号部分表示运动方向,+ 正号表示向右移动,- 负号表示向左移动,且移动速度相同。
  • 数字部分表示行星大小。 这些行星都在一条水平直线上,给定碰撞规则,大行星和小行星碰撞时小行星爆炸消失,大行星不变,当行星大小相同时,两个行星同时爆炸,全部消失。

问碰撞后剩下的所有行星排列。

题目提示由于行星移动速度相同,所以朝着相同方向运动的行星无论大小都不会碰撞。

解题思路分析

我们可以使用一个栈进行模拟这个碰撞过程:

  • 当行星是向右移动时我们将行星放入栈
  • 当遇到向左移动的行星时我们首先与栈顶的行星进行碰撞模拟,直至消失或者栈中没有元素为止。 依次模拟这个过程即可。

具体实现

  1. 从左到右遍历所有行星;
  2. 将大于 0 的行星放入栈中;
  3. 将小于 0 的行星不断与栈顶向右移动的行星(如果存在)进行比较大小,模拟碰撞过程,直至消失或者栈空。
  4. 如果模拟碰撞结束后当前小于 0 的行星仍然还在,那么将其放入栈中。

我们采用 vector 代替栈进行模拟,因为正好可以当作返回值进行返回。

  • 在模拟碰撞的过程中首先使用一个变量记录当前行星是否还存在。
  • 使用 vectorpop_back() 函数可以模拟栈中的弹出栈顶元素操作;
  • 使用 vectorback() 函数可以模拟栈中的取出栈顶元素的操作。

复杂度分析

  • 时间复杂度:O(n)O(n),其中 n 为数组 asteroids 的大小。出入栈次数均不超过 n 次。
  • 空间复杂度:O(1)O(1)。返回值不计入空间复杂度,仅需常数空间。

代码实现

class Solution {
public:
    vector<int> asteroidCollision(vector<int>& asteroids) {
        //用矢量数组vector当栈和返回数组
        vector<int> ans;
        ans.clear();
        //顺序遍历每个行星
        for(int &a : asteroids){
            //记录当前行星是否还在
            bool alive = true;
            //如果当前行星还在 && 当前行星向左 && 栈中有元素 && 最后一个是朝右的
            while(alive && a < 0 && ans.size() && ans.back() > 0){
                alive = -a > ans.back();
                //不断与栈顶的行星碰撞
                if(ans.back() <= -a) ans.pop_back();
            }
            //如果当前行星还在就压入栈
            if(alive) ans.push_back(a);
        }
        return ans;
    }
};

总结

  • 该题的难点在于想到使用栈数据结构进行模拟,当想到使用栈时,题目就变得简单了,因为剩下的就是模拟了。
  • 需要注意在代码实现过程中注意边界问题,还有负数的行星与整数的行星比大小时需要取绝对值。
  • 该题可以使用 vector 进行模拟栈操作,从而节省了栈空间,这是因为 vector 在该题中是作为返回值的存在,不计入空间复杂度,算是一个空间复杂度的优化。
  • 测试结果:

735.png

结束语

人这一生中会遇到几次不错的机遇,但只要你稍微犹豫,机会就会从眼前溜走。所以,当你能够抓住机遇时,要确定自己具备接得住的能力。我们无法预知幸运会在哪个瞬间降临,但我们可以不断提升自己。新的一天,加油!