735 行星碰撞——Leetcode天天刷【栈】(2022.7.13)

735 行星碰撞——Leetcode天天刷【栈】(2022.7.13)

前言

虽然是黄色,中等题目,但我还是觉得简单,不过需要注意一些细节。

题目信息

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

简单描述一下题目:就是一个数组,元素表示行星的质量和移动方向,负值表示向左移动,正值表示向右移动,行星碰撞时,如果质量相同则都会消失,否则留下质量较大的。

输入与输出

和之前的一样,为了方便在本地测试,所以在输入与输出的设置做了处理。

输入

我们对测试用例的数量不做限制,对每个测试用例:

第一行输入整数n,表示行星的数量,也就是数组的尺寸。

第二行输入n个整数,表示行星的质量和行星移动的方向。

输出

每个测试用例输出一行,输出碰撞后剩下的行星,如果没有行星,则不用输出。

测试用例

输入用例
3
5 10 -5

2
8 -8

3
10 2 -5

4
-2 -1 1 2

4
-2 -2 1 -2
输出用例
5 10
10
-2 -1 1 2
-2 -2 -2

提示

  • 2 <= asteroids.length <= 104
  • -1000 <= asteroids[i] <= 1000
  • asteroids[i] != 0

法一:栈

看题目的描述,首先我们需要对题目先分析,我们在遍历行星的时候,行星在数组的索引,其实可以认为是初始位置,行星碰撞的条件在于相向运动,且还有一个隐藏条件是两个行星的初始位置的关系和移动方向相反。

情况如下

在这里插入图片描述

结合上面的分析,我们可以得出基于 的解题思路。

我们可以在遍历行星的时候,如果当前行星 “未碰撞”,注意这里指的是未碰撞,即在后面还是有可能会碰撞。所以我们可以先将行星存储起来,对于当前行星,我们显然需要将其和栈顶的行星判断是否会碰撞,如果会碰撞,我们显然需要判断碰撞后会留下哪颗行星。反映到程序其实就是出栈和压栈。

那么,我们就将入栈的条件来列举:

  1. 栈空。
  2. 栈的顶部为负值,表示栈顶的行星是向左运动,那么无论当前行星向哪个方向移动,都不会和前面的发生碰撞。
  3. 当前行星为正值,表示向右运动,同2,不会和前面的行星碰撞。

这上面其实就是当前行星不会和前面的行星发生碰撞的情况,如果发生碰撞,我们需要处理。

可以知道,此时栈顶为正值,当前行星为负值,我们需要比较绝对值,如果栈顶小于当前行星,需要出栈,直到栈空或者不会碰撞,或者碰撞后当前行星消失。如果等于,还需要出栈,行星消失,如果大于,行星消失。到这里,如果行星还没消失,那就可以入栈了。

时间复杂度:O(n)。

空间复杂度:O(n)。

通过截图。

在这里插入图片描述

Code(C++)

#include<iostream>
#include<vector>
#include<stack>

using namespace std;

class Solution 
{
public:
    /// <summary>
    /// 栈
    /// 遍历数组,当栈空或者当前元素和栈符号相同时,压栈
    /// 特殊情况,由于方向,所以当栈顶为负值时,也可以压栈
    /// 否则判断是否需要出栈
    /// 完事后,在输出到数组中即可
    /// </summary>
    /// <param name="asteroids"></param>
    /// <returns></returns>
    vector<int> asteroidCollision(vector<int>& asteroids) 
    {
        stack<int> stk;         // 堆栈存储最终留下的行星
        // 遍历行星,判断行星堆栈和出栈
        for (int asteroid : asteroids)
        {
            // 栈空或者不会碰撞
            if (stk.empty() || stk.top() < 0 || asteroid > 0)
            {
                stk.push(asteroid);
            }
            // 发生碰撞
            else
            {
                // 很明显,碰撞时,栈顶一定是朝右,正值,当前行星一定是朝左,负值
                // 碰撞时需要根据质量判断出栈,写一个循环
                while (!stk.empty() && stk.top() > 0 && stk.top() < -asteroid)
                {
                    stk.pop();
                }
                // 栈还有行星的情况下,需要判断是否相等
                if (!stk.empty() && stk.top() > 0 && stk.top() == -asteroid)
                {
                    stk.pop();
                }
                // 栈空了,或者此时同向
                else if (stk.empty() || stk.top() < 0)
                {
                    stk.push(asteroid);
                }
            }
        }
        int n = stk.size();     // 获取最终答案的数组尺寸
        vector<int> ans(n);
        // 逆序存储
        for (int i = n - 1; i >= 0; --i)
        {
            ans[i] = stk.top();
            stk.pop();
        }
        return ans;
    }
};

int main(int argc, char** argv)
{
    int n;
    Solution sol;
    while(cin >> n)
    { 
        vector<int> asteroids(n);
        for (int& ast : asteroids)
        {
            cin >> ast;
        }
        auto ans = sol.asteroidCollision(asteroids);
        int n1 = ans.size();
        if (n1 == 0)
        {
            continue;
        }
        for (int i = 0; i < n1 - 1; ++i)
        {
            cout << ans[i] << ' ';
        }
        cout << ans[n1 - 1] << endl;
    }

	return 0;
}

后话

额,今天就没有一题多解了,本来想过双指针,但是却发现并不是很适合,所以就这样了。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值