leetcode264-丑数||

·  阅读 182

题目描述

编写一个程序,找出第 n 个丑数。

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

思考

我们要找第n位的丑数,那就是把丑数从小到大排序,取出其中第 n大的数即是我们想要的结果。那么现在的问题就是我们怎么去找第 n大的这个数。

因为丑数是只包含 2、3、5的正整数。因此我们需要排序的其实是 2、3、5的倍数们。

方法一 (这是我第一次的想法,笨办法,稍显奇葩)

我们已1作为根节点,分别乘以 2,3,5。得到第一层数据,再分别乘以 2,3,5得到第二层数据。 这时候我们发现两个问题,

1、下一层的数据不一定比上一层小; 2、一层的数据有可能有重叠。

只要解决这两个问题,我们就可以保证每一次压入丑数数组的数据是最小的。

我们先声明一个数组 temp作为数据池,存储那些已经计算出来,但是并非最小的丑数。 针对第一个问题,我们可以在每一次将最小数压入数组后,将其乘以 2,3,5。并放到 temp数据池中,然后遍历数据池中元素,取出最小,压入丑数数组,在数据池中删除该数。重复上述过程即可。

第二个问题

第二个问题产生的原因是基于乘法交换律产生的,因此我们可以对 temp数据池中的数字做一个标记,记录它们最后一个乘数是谁 lastMul。 然后在 2,3,5中选择小于 lastMul的乘数即可。

代码如下

        let uglyNum = [1];

        let tempMap = new Map(); //  临时数据存储区
        tempMap.set(2, 2);
        tempMap.set(3, 3);
        tempMap.set(5, 5);

        let mulArr = [2, 3, 5];

        nextUgly(n);

        return uglyNum[n - 1];
        
        /*
        {
            value:   // 当前值
            lastMul:  // 最后乘数
        }
        */

        function nextUgly(n) {
            if (uglyNum.length >= n) {
                return;
            }

            let minVal = -1;
            for (let [value, lastMul] of tempMap) {

                if (minVal == -1 || minVal > value) {
                    minVal = value
                }
            }

            uglyNum.push(minVal);

            let lastMul = tempMap.get(minVal);
            tempMap.delete(minVal);
            for (let i = 0; i < mulArr.length; i++) {
                if (lastMul >= mulArr[i]) {
                    tempMap.set(minVal * mulArr[i], mulArr[i]);
                }
            }

            nextUgly(n);
        }

复制代码

方法二 (动态规划)

这个是基于前面的笨办法想到的。 因为丑数数组中的每一个数其实都是基于前面的元素乘以 2,3,5产生的。因此我们可以用三个标记 i2,i3,i5作为标记。比较 uglyNum[i2] * 2, uglyNum[i3] * 3, uglyNum[i5] * 5的最小值, 比如说是 uglyNum[i5] * 5, 我们将 uglyNum[i5] * 5压入uglyNum中,并将 i5加一。代表这个数已经乘过5了,并且乘积已经被放入丑数数组了,我们现在移向下一个丑数,计算它和5的乘积。

uglyNum[i] = min(uglyNum[i2] * 2, uglyNum[i3] * 3, uglyNum[i5] * 5);
复制代码

代码如下

let uglyNum = [1];

        let hasNum = new Set();
        hasNum.add(1);

        nthNum(n, 0, 0, 0);

        function nthNum(n, i2, i3, i5) {
            if (uglyNum.length >= n) {
                return;
            }
            let tempN2 = uglyNum[i2] * 2;
            let tempN3 = uglyNum[i3] * 3;
            let tempN5 = uglyNum[i5] * 5;

            let minNum = Math.min(Math.min(tempN2, tempN3), tempN5);

            if (minNum === tempN2) {
                i2++;
            } else if (minNum === tempN3) {
                i3++;
            } else if (minNum === tempN5) {
                i5++;
            }
            
            if (!hasNum.has(minNum)) {
                uglyNum.push(minNum);
                hasNum.add(minNum);
            }

            nthNum(n, i2, i3, i5);
        }


        return uglyNum[n-1];

复制代码
分类:
阅读
标签:
分类:
阅读
标签:
收藏成功!
已添加到「」, 点击更改