返回

行星碰撞 Java 题解:领悟背后的物理直觉

后端

引言

在浩瀚的太空,行星的碰撞是常见的现象。在计算机科学领域,行星碰撞问题在 LeetCode 等编程平台上也广受关注。这个问题看似复杂,但如果你掌握了背后的物理直觉,它将变得清晰明了。

物理直觉

行星碰撞的物理原理非常简单:

  • 质量越大,动能越大: 一个行星的动能与它的质量成正比。
  • 动能守恒: 碰撞前后,系统的总动能守恒。

算法思路

基于上述物理直觉,我们可以设计一个贪心算法来解决这个问题:

  1. 初始化一个栈: 栈中存储的是尚未处理的行星。
  2. 循环遍历行星:
    • 如果行星的绝对值大于栈顶行星的绝对值:
      • 弹出栈顶行星,表示较小的行星被较大的行星撞毁。
      • 将当前行星压入栈中。
    • 否则:
      • 将当前行星压入栈中。
  3. 返回栈中剩余的行星: 这些行星没有被撞毁。

Java 实现

import java.util.Stack;

public class Solution {

    public int[] asteroidCollision(int[] asteroids) {
        Stack<Integer> stack = new Stack<>();
        for (int asteroid : asteroids) {
            int absAsteroid = Math.abs(asteroid);
            while (!stack.isEmpty() && stack.peek() < absAsteroid) {
                stack.pop();
            }
            if (stack.isEmpty() || asteroid > 0 || stack.peek() < absAsteroid) {
                stack.push(asteroid);
            }
        }
        int[] result = new int[stack.size()];
        for (int i = stack.size() - 1; i >= 0; i--) {
            result[i] = stack.pop();
        }
        return result;
    }
}

自定义比较器

为了判断行星是否会被撞毁,我们需要定义一个自定义比较器:

Comparator<Integer> comparator = (a, b) -> {
    int absA = Math.abs(a);
    int absB = Math.abs(b);
    if (absA == absB) {
        return 0;
    } else if (absA > absB) {
        return -1;
    } else {
        return 1;
    }
};

实例分析

考虑以下行星数组:[-2, -1, 1, 2].

  • 当我们遇到 -1 时,它比栈顶的 -2 小,因此它被弹出。
  • 然后我们遇到 1,它比 -2 大,因此它被压入栈中。
  • 接下来,我们遇到 2,它比 1 大,因此它也被压入栈中。

最终,栈中剩余的行星为 [-2, 1, 2].

结论

通过理解行星碰撞背后的物理直觉,我们可以巧妙地利用栈数据结构和自定义比较器来解决 LeetCode 中的这个难题。这种基于物理定律的算法既优雅又高效,值得深入研究和应用。