🌈【LeetCode.丑数II 】-JavaScript =>动态规划+最小堆

390 阅读2分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战


说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)

作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金

GitHub:P-J27、 CSDN:PJ想做前端攻城狮

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


【LeetCode 264.丑数II 】- JavaScript(动态规划+最小堆)

题目描述:编写一个程序,找出第 n 个丑数。

分析:丑数就是只包含质因数 2, 3, 5 的正整数。


解法 1: 动态规划

思路:首先我们得知道因为丑数只包含质因数 2, 3, 5,这是很关键的,因此对于下个丑数来说,一定是前面某个丑数的三倍四倍或者五倍。

那我们使用三个指针 ptr2、ptr3、ptr5,它们指向的数对应235即只能乘 2、3 和 5。在循环过程中,每次选取 2 * res[ptr2]3 * res[ptr3]5 * res[ptr5]这三个数中结果最小的数,并且将对应的指针向前移动。有效循环是 n 次,当循环结束后,res 数组中就按从小到大的顺序保存了丑数。


var nthUglyNumber = function(n) {
  const res = new Array(n);
  res[0] = 1;

  let ptr2 = 0, // 下个数字永远 * 2
    ptr3 = 0, // 下个数字永远 * 3
    ptr5 = 0; // 下个数字永远 * 5

  for (let i = 1; i < n; ++i) {
    res[i] = Math.min(res[ptr2] * 2, res[ptr3] * 3, res[ptr5] * 5);
    
    if (res[i] === res[ptr2] * 2) {
      ++ptr2;
    }
    if (res[i] === res[ptr3] * 3) {
      ++ptr3;
    }
    if (res[i] === res[ptr5] * 5) {
      ++ptr5;
    }
  }

  return res[n - 1];
};

分析一下这样的写法整体的复杂度,时间复杂度是O(N),空间复杂度是O(N)。看起来还不错的,都是线性的,感觉还能接受。


解法 2: 最小堆

思路:我们利用最小堆的思想,借助最小堆,可以在 O(LogN) 时间复杂度内找到当前最小的元素。如果我们遇到卡时间的数据,最小堆是最佳的选择。核心思路如下:

  • 准备最小堆 heap。使用Set来去重,相当于来用于记录丑数是否Visited。
  • 首先我们将 1 放入堆中,然后从 0 开始,遍历数组
    • 取出堆顶元素,放入数组 res 中
    • 用堆顶元素依此乘以 2、3、5,推入set去重
  • 为了提高效率,我们使用的是hashset,其时间复杂度为O(1)
class Solution {
    public int nthUglyNumber(int n) {
        // 最小堆 + 集合去重,用的都是Long
        PriorityQueue<Long> pq = new PriorityQueue<Long>();
        HashSet<Long> set = new HashSet<Long>();
        int[] ruler = {2, 3, 5};
        pq.offer(1l);
        long[] ans = new long[n];
        for (int i = 0; i < n; i++) {
            ans[i] = pq.poll();
            for (int i1 : ruler) {
                // 加入3个值(最小值 * 2, * 3 * 5)
                if(!set.contains(ans[i] * i1) && ans[i] < Integer.MAX_VALUE){
                    pq.offer(ans[i] * i1);
                    set.add(ans[i] * i1);
                }
            }
        }
    return (int)ans[n - 1];
    }
}

分析一下最小堆整体的复杂度,时间复杂度是O(logN), 空间复杂度是O(N)。在时间上做了优化。


感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤