每日一刷经验分享:1252简单. 奇数值单元格的数目

145 阅读4分钟

1252简单. 奇数值单元格的数目

题意

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

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

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

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

提示

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

AC代码

👀Java版本:

class Solution {
    public int[] asteroidCollision(int[] asteroids) {
        Deque<Integer> queue=new LinkedList<>();
    //    queue.addFirst();
    //    queue.getFirst();
    //    queue.peekFirst();
       boolean flag = false;
       int a;
        for(int i:asteroids){
            if(i>0) queue.addFirst(i);
            else{
                flag=false;
                while(!queue.isEmpty()&&queue.getFirst()>=0){
                    a = queue.getFirst();
                    if(a+i>0){
                        break;
                    }else if(a+i==0){
                        flag = true;
                        queue.removeFirst(); 
                        break;
                    }
                    queue.removeFirst(); //如果小于等于移除第一个元素
                }
                if(flag) { //等于0的处理
                    continue;
                }
                //小于0的处理
                if(queue.isEmpty()||queue.getFirst()<0){
                    queue.addFirst(i);
                }
            }
        }
        int len = queue.size();
        int[] t = new int[len];
        int i=0;
        while(!queue.isEmpty()) {
            t[i++]=queue.removeLast();
        }
        return t;     
    }
}

👀Python代码:

class Solution:
    def asteroidCollision(self, asteroids: List[int]) -> List[int]:
        stack = []
        for n in asteroids:
            if not stack or n > 0:
                stack.append(n)
            else:
                remain = True
                while stack:
                    if stack[-1] < 0:
                        break
                    elif stack[-1] == abs(n):
                        stack.pop()
                        remain = False
                        break
                    elif stack[-1] > abs(n):
                        remain = False
                        break
                    else:
                        stack.pop()
                if remain:
                    stack.append(n)
        return stack

👀C语言: 上述分析转化为:栈顶元素大于0时,只有栈顶元素小于当前元素的绝对值,或者栈为空,当前元素才会存活。最终栈内元素即为最终答案。

int* asteroidCollision(int* asteroids, int asteroidsSize, int* returnSize){
    int * ans = (int *)malloc(sizeof(int) * asteroidsSize);//申请额外空间
    *returnSize = 0;
    int top = 0;
    for(int i = 0; i < asteroidsSize; i++)//遍历整个数组
    {
        int t = 1;
        while(asteroids[i] < 0 && top > 0 && ans[top-1] > 0 && t)//当前元素为负,栈不为空,栈顶元素为正,当前元素活
        {
            if(abs(asteroids[i]) > abs(ans[top-1]))//当前元素比栈顶大,栈顶死
            {
                top--;
            }
            else if(abs(asteroids[i]) == abs(ans[top-1]))//一样大,一起死
            {
                top--;
                t = 0;
            }
            else//栈顶大,我死
            {
                t = 0;
            }
        }
        if(t)//我最后还活着,入栈
        {
            ans[top++] = asteroids[i];
        }
    }
    *returnSize = top;
    return ans;
}

分析

Java代码思路分析

首先根据题意可以看出,大于等于0的值往右边走,小于0的往左边走,并且正负值相遇,绝对值大的能灭掉绝对值小的,所以就想到了使用栈做处理,大于等于0的直接入栈,遇见小于0的,从栈里边取出值,和小于0的比较,如果和小于0的这个数相加之后小于零,把栈顶元素删除,并且再去下一个栈顶元素。

python代码思路分析

从左往右遍历,所以如果遇到往右走的行星,就可以直接加入到栈中(栈中不存在会和该行星碰撞的行星) 如果遇到往左走的行星,那就不断地根据栈顶情况分类讨论:

  1. stack为空或者stack最后一位是往左的,可以直接结束循环,将行星加入栈中
  2. stack最后一位和该行星一样大,则推出栈的最后一个行星,直接结束循环
  3. stack最后一位比该行星大,则不做任何操作,直接结束循环
  4. stack最后一位比该行星小,则推出栈的最后一个行星,继续循环

可以采用布尔变量remain来判断是否需要添加当前行星到栈顶。

题解过程分析

  1. Deque queue=new LinkedList<>();定义双端队列,用于存储整数。
  2. for(int i:asteroids){ if(i>0) queue.addFirst(i); 遍历数组,如果大于0 直接加入到队列中。
  3. while(!queue.isEmpty()&&queue.getFirst()>=0){} 如果当前元素小于0,需要从队列头部取出元素,和当前值比较。
  4. else if(a+i==0){flag = true; queue.removeFirst(); break; } //这个是当等于0的要特殊处理,因为等于零不仅要删除队列头部的元素还要用flag记录,不让当前元素加入到队列中去,flag等于true表示当前元素等于队头元素。
  5. if(flag) { //等于0的处理 continue; } 、、这个注意等于0 表示上边遍历的时候,有队列的头部元素和当前元素相加等于0,也就是相反数,根据题意的分析,需要删除队列头部的元素。并且当前值也不再加入队列。
  6. //小于0的处理 if(queue.isEmpty()||queue.getFirst()<0){ queue.addFirst(i); } 遍历完小于0的还没消除就加到队列中。
  7. while(!queue.isEmpty()) { t[i++]=queue.removeLast(); } 反向取值,加入到数组当中返回即可。因为RemoveLast,会删除队尾元素并且返回队尾元素的值。

复杂度分析

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(n)O(n)

总结

  • 时间消耗量: 采用栈的思路,遍历每一个数字,遇见大于等于0的加入栈,小于零的与栈头比较做处理,时间消耗量一般。
  • 内存消耗量 采用Deque存储相比于用一个整型数组当作栈进行处理占用的内存更大,主要是不想自己再维持一个下标变量当作栈了(偷懒了), image.png

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿