剑指 Offer 49. 丑数(多路归并(三指针) & 优先队列)

剑指 Offer 49. 丑数
【多路归并(三指针) & 优先队列】

  • 求第n个丑数是多少
    • 丑数:质因子只包含2、3、5的数
  • 思路:
    • 若一个数x为丑数,那么2*x3*x5*x都为丑数
      - 就有了三条链表:
      - *2: ugly[1]*2 -> ugly[2]*2 -> ugly[3]*2 -> ugly[4]*2 ...
      - *3: ugly[1]*3 -> ugly[2]*3 -> ugly[3]*3 -> ugly[4]*3 ...
      - *5: ugly[1]*5 -> ugly[2]*5 -> ugly[3]*5 -> ugly[4]*5 ...
    • 合并链表:
      • 将这三条有序链表合并,使得合并后的链表有序
        • 合并链表思想,两条链表合并&k条链表合并
          • 手动合并(三指针) & 最小堆(优先队列)
      • 不同链表间存在重复元素怎么办,会不会被重复计入?
        • 手动合并:不会
          • 每条链表都是升序排列,合并时也是从小到大排列。每次从不同链表中取最小的
          • 所以不同链表中,若存在重复元素,在该元素前面的元素都比它小,被提前拿走了,所以不同链表间的重复元素一定是在同一个循环里被判断的,可当场去重
        • 优先队列:可能会
          • 所以要加判断
          • 同手动合并的规则,因为是从小到大排列,如果存在重复元素,只可能是排列后的最后一个元素,和堆顶元素存在重复,特判即可

手动合并:

    int nthUglyNumber(int n) {
        vector<long> ugly(n+2, 0);
        int k = 1;
        int p2 = 1, p3 = 1, p5 = 1;
        long product2 = 1, product3 = 1, product5 = 1;
        while(k <= n){
            long minn = min(product2, min(product3, product5));
            ugly[k++] = minn;
            if(minn == product2){
                product2 = 2 * ugly[p2++];
            }
            if(minn == product3){
                product3 = 3 * ugly[p3++];
            }
            if(minn == product5){
                product5 = 5 * ugly[p5++];
            }
        }
        return ugly[n];
    }

优先队列(最小堆):

//上面的思路:若X为丑数,则2*x,3*x,5*x也为丑数
    int nthUglyNumber(int n){
        // vector<long> ugly(n+2, 0);
        long ugly = 1;
        vector<int> factor{2,3,5};
        int k = 1;
        priority_queue<long, vector<long>, greater<long>> q; 
        q.push(1ll);
        while(k <= n){
            long minn = q.top();
            q.pop();
            // ugly[k++] = minn;
            ugly = minn;
            k++;
            while(!q.empty() && q.top() == minn) q.pop();
            for(int fac: factor){
                q.push(minn * fac);
            }
        }
        // return ugly[n];
        return ugly;
    }

//手动合并的思路:三指针
    int nthUglyNumber(int n){
        vector<long> ugly(n+2, 0);
        vector<int> factor{2, 3, 5};
        priority_queue<node> q;
        
        int k = 1;
        for(int i = 0; i < factor.size(); i++){
            q.push(node{1, factor[i], 1});
        }
        while(k <= n){
            node t = q.top();
            q.pop();
            if(t.pro != ugly[k-1]) ugly[k++] = t.pro;

            q.push(node{ugly[t.id] * t.fac, t.fac, t.id+1});
        }
        return ugly[n];

    }
    struct node{
        long pro;
        int fac;
        int id;
        friend bool operator<(const node &a, const node &b){
            return a.pro > b.pro;
        }
    };
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值