题目描述:
给定一个整数数组 asteroids,表示在同一行的行星。
对于数组中的每一个元素,其绝对值表示行星的大小,正负表示行星的移动方向(正表示向右移动,负表示向左移动)。每一颗行星以相同的速度移动。
找出碰撞后剩下的所有行星。碰撞规则:两个行星相互碰撞,较小的行星会爆炸。如果两颗行星大小相同,则两颗行星都会爆炸。两颗移动方向相同的行星,永远不会发生碰撞。
下面是题目给出的示例: 注意示例4,有助于搞清楚题目意思,我刚开始做的时候就弄错了题目含义
这个题目倒不是有多大的难度,而是官方题解里给出的一个语法:
这个语法看起来有点熟悉,但是我却不知道它具体是怎么运行的了,而如果不用这种语法,代码会很复杂,所以这里我们来说一说这种标记跳转语法:
我们先看一下上面这段代码的执行过程:
public static int[] asteroidCollision(int[] asteroids) {
Stack<Integer> stack = new Stack();
for (int ast: asteroids) {
collision: {
while (!stack.isEmpty() && ast < 0 && 0 < stack.peek()) {
if (stack.peek() < -ast) {
stack.pop();
// 继续while循环,这时stack栈顶元素已经被移除
continue;
} else if (stack.peek() == -ast) {
stack.pop();
}
// 跳出循环,并回到collision位置,collision代码块执行结束
break collision;
}
// 只while循环条件不满足,才会执行到这里
stack.push(ast);
}
}
int[] ans = new int[stack.size()];
for (int t = ans.length - 1; t >= 0; --t) {
ans[t] = stack.pop();
}
return ans;
}
这里有几个关键的执行步骤:
- 先循环遍历数组中的元素,没遍历一个元素都要与栈中已有元素进行比较
- while循环: 如果栈不为空,且元素为负数,而栈顶元素为整数时进入while循环
- 进入while循环后, (1)如果栈顶元素小于当前数组中的元素的绝对值,按照规则需要将栈顶元素移除, 移除之后,栈的栈顶元素发生改变,继续判断当前栈是否满足循环条件。如果不满足while循环条件,则会执行stack.push 语句; (2)如果栈顶元素等于当前数组元素的绝对值,同样要移除栈顶元素,不过这时按照规则,当前元素也不能进栈,这时候就需要结束collision代码块,继续外层的for循环。(3) 如果栈顶元素大于当前元素的绝对值,不需要移除栈顶元素,且当前元素也不用进栈,这时直接结束collision代码块即可。
所以从上面的执行过程中可以看出来, A:{ while/for {..... break A } xxxxx } , 一旦break A之后,相当于直接跳出A :{ .... } 代码块。继续执行这之后的语句。而breakA 之后的语句和 while循坏外的语句不会再执行。