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代码思路分析
从左往右遍历,所以如果遇到往右走的行星,就可以直接加入到栈中(栈中不存在会和该行星碰撞的行星) 如果遇到往左走的行星,那就不断地根据栈顶情况分类讨论:
- stack为空或者stack最后一位是往左的,可以直接结束循环,将行星加入栈中
- stack最后一位和该行星一样大,则推出栈的最后一个行星,直接结束循环
- stack最后一位比该行星大,则不做任何操作,直接结束循环
- stack最后一位比该行星小,则推出栈的最后一个行星,继续循环
可以采用布尔变量remain来判断是否需要添加当前行星到栈顶。
题解过程分析
- Deque queue=new LinkedList<>();定义双端队列,用于存储整数。
- for(int i:asteroids){ if(i>0) queue.addFirst(i); 遍历数组,如果大于0 直接加入到队列中。
- while(!queue.isEmpty()&&queue.getFirst()>=0){} 如果当前元素小于0,需要从队列头部取出元素,和当前值比较。
- else if(a+i==0){flag = true; queue.removeFirst(); break; } //这个是当等于0的要特殊处理,因为等于零不仅要删除队列头部的元素还要用flag记录,不让当前元素加入到队列中去,flag等于true表示当前元素等于队头元素。
- if(flag) { //等于0的处理 continue; } 、、这个注意等于0 表示上边遍历的时候,有队列的头部元素和当前元素相加等于0,也就是相反数,根据题意的分析,需要删除队列头部的元素。并且当前值也不再加入队列。
- //小于0的处理 if(queue.isEmpty()||queue.getFirst()<0){ queue.addFirst(i); } 遍历完小于0的还没消除就加到队列中。
- while(!queue.isEmpty()) { t[i++]=queue.removeLast(); } 反向取值,加入到数组当中返回即可。因为RemoveLast,会删除队尾元素并且返回队尾元素的值。
复杂度分析
- 时间复杂度:O(n)O(n)
- 空间复杂度:O(n)O(n)
总结
- 时间消耗量: 采用栈的思路,遍历每一个数字,遇见大于等于0的加入栈,小于零的与栈头比较做处理,时间消耗量一般。
- 内存消耗量
采用Deque存储相比于用一个整型数组当作栈进行处理占用的内存更大,主要是不想自己再维持一个下标变量当作栈了(偷懒了),
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿