LeetCode——264. 丑数 II

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

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

示例:

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。

说明:

1 是丑数。
n 不超过1690。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ugly-number-ii

1.暴力(brute force)

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> v;
        for (long long a=1;a<=INT_MAX;a=a*2)
            for (long long b=a;b<=INT_MAX;b=b*3)
                for (long long c=b;c<=INT_MAX;c=c*5)
                    v.push_back(c);
        sort(v.begin(),v.end());
        return v.at(n-1);
    }
};

2.优先队列(小顶堆)

c++优先队列(priority_queue)用法详解

https://blog.csdn.net/weixin_36888577/article/details/79937886

既然是队列那么先要包含头文件#include, 他和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队

优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的

和队列基本操作相同:

  • top 访问队头元素
  • empty 队列是否为空
  • size 返回队列内元素个数
  • push 插入元素到队尾 (并排序)
  • emplace 原地构造一个元素并插入队列
  • pop 弹出队头元素
  • swap 交换内容

定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆
一般是:

//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

基本类型例子:

#include<iostream>
#include <queue>
using namespace std;
int main()
{
    //对于基础类型 默认是大顶堆
    priority_queue<int> a;
    //等同于 priority_queue<int, vector<int>, less<int> > a;

    //    这里一定要有空格,不然成了右移运算符↓
    priority_queue<int, vector<int>, greater<int> > c;  //这样就是小顶堆
    priority_queue<string> b;

    for (int i = 0; i < 5; i++)
    {
        a.push(i);
        c.push(i);
    }
    while (!a.empty())
    {
        cout << a.top() << ' ';
        a.pop();
    }
    cout << endl;

    while (!c.empty())
    {
        cout << c.top() << ' ';
        c.pop();
    }
    cout << endl;

    b.push("abc");
    b.push("abcd");
    b.push("cbd");
    while (!b.empty())
    {
        cout << b.top() << ' ';
        b.pop();
    }
    cout << endl;
    return 0;
}

输出

输出

4 3 2 1 0
0 1 2 3 4
cbd abcd abc

2.pari的比较,先比较第一个元素,第一个相等比较第二个

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
    priority_queue<pair<int, int> > a;
    pair<int, int> b(1, 2);
    pair<int, int> c(1, 3);
    pair<int, int> d(2, 5);
    a.push(d);
    a.push(c);
    a.push(b);
    while (!a.empty())
    {
        cout << a.top().first << ' ' << a.top().second << '\n';
        a.pop();
    }
}

输出

2 5
1 3
1 2

3.对于自定义类型

#include <iostream>
#include <queue>
using namespace std;

//方法1
struct tmp1 //运算符重载<
{
    int x;
    tmp1(int a) {x = a;}
    bool operator<(const tmp1& a) const
    {
        return x < a.x; //大顶堆
    }
};

//方法2
struct tmp2 //重写仿函数
{
    bool operator() (tmp1 a, tmp1 b)
    {
        return a.x < b.x; //大顶堆
    }
};

int main()
{
    tmp1 a(1);
    tmp1 b(2);
    tmp1 c(3);
    priority_queue<tmp1> d;
    d.push(b);
    d.push(c);
    d.push(a);
    while (!d.empty())
    {
        cout << d.top().x << '\n';
        d.pop();
    }
    cout << endl;

    priority_queue<tmp1, vector<tmp1>, tmp2> f;
    f.push(c);
    f.push(b);
    f.push(a);
    while (!f.empty())
    {
        cout << f.top().x << '\n';
        f.pop();
    }
}

输出

3
2
1

3
2
1

利用优先队列有自动排序的功能
每次取出队头元素,存入队头元素2、队头元素3、队头元素5
但注意,像12这个元素,可由4乘3得到,也可由6乘2得到,所以要注意去重

class Solution {
public:
    int nthUglyNumber(int n) {
        priority_queue <double,vector<double>,greater<double> > q;
        double answer=1;
        for (int i=1;i<n;++i)
        {
            q.push(answer*2);
            q.push(answer*3);
            q.push(answer*5);
            answer=q.top();
            q.pop();
            while (!q.empty() && answer==q.top())
                q.pop();
        }
        return answer;
    }
};

还可以更进一步采用set来识别有无重复

class Solution {
public:
    int nthUglyNumber(int n) {
        priority_queue <double,vector<double>,greater<double> > q;
        set<int> s;
        s.insert(1);
        vector<int> mask({2,3,5});
        double answer=1;
        for (int i=1;i<n;++i)
        {
            for (int &j:mask)
                if (s.count(answer*j)==0)
                {
                    q.push(answer*j);
                    s.insert(answer*j);
                }
            answer=q.top();
            q.pop();
        }
        return answer;
    }
};

3.动态规划(三指针)

我们先模拟手写丑数的过程
1打头,1乘2 1乘3 1乘5,现在是{1,2,3,5}
轮到2,2乘2 2乘3 2乘5,现在是{1,2,3,4,5,6,10}
手写的过程和采用小顶堆的方法很像,但是怎么做到提前排序呢

小顶堆的方法是先存再排,dp的方法则是先排再存
我们设3个指针p_2,p_3,p_5
代表的是第几个数的2倍、第几个数3倍、第几个数5倍
动态方程dp[i]=min(dp[p_2]2,dp[p_3]3,dp[p_5]*5)
小顶堆是一个元素出来然后存3个元素
动态规划则是标识3个元素,通过比较他们的2倍、3倍、5倍的大小,来一个一个存

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> dp(n);
        dp.at(0)=1;
        int p_2,p_3,p_5;
        p_2=p_3=p_5=0;
        for (int i=1;i<n;++i)
        {
            dp.at(i)=min(min(2*dp.at(p_2),3*dp.at(p_3)),5*dp.at(p_5));
            if (dp.at(i)==2*dp.at(p_2))
                ++p_2;
            if (dp.at(i)==3*dp.at(p_3))
                ++p_3;
            if (dp.at(i)==5*dp.at(p_5))
                ++p_5;
        }
        return dp.at(n-1);
    }
};

Java

    public int nthUglyNumber(int n) {
        int[] dp = new int[n];
        dp[0] = 1;
        int i2 = 0, i3 = 0, i5 = 0;
        for (int i = 1; i < n; i++) {
            int min = Math.min(dp[i2] * 2, Math.min(dp[i3] * 3, dp[i5] * 5));
            if (min == dp[i2] * 2) i2++;
            if (min == dp[i3] * 3) i3++;
            if (min == dp[i5] * 5) i5++;
            dp[i] = min;
        }

        return dp[n - 1];
    }

C++

这道题是之前那道 Ugly Number 的拓展,这里让找到第n个丑陋数,还好题目中给了很多提示,基本上相当于告诉我们解法了,根据提示中的信息,丑陋数序列可以拆分为下面3个子列表:

(1) 1x2, 2x2, 2x2, 3x2, 3x2, 4x2, 5x2...

(2) 1x3, 1x3, 2x3, 2x3, 2x3, 3x3, 3x3...

(3) 1x5, 1x5, 1x5, 1x5, 2x5, 2x5, 2x5...

仔细观察上述三个列表,可以发现每个子列表都是一个丑陋数分别乘以 2,3,5,而要求的丑陋数就是从已经生成的序列中取出来的,每次都从三个列表中取出当前最小的那个加入序列,请参见代码如下:

解法一:

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> res(1, 1);
        int i2 = 0, i3 = 0, i5 = 0;
        while (res.size() < n) {
            int m2 = res[i2] * 2, m3 = res[i3] * 3, m5 = res[i5] * 5;
            int mn = min(m2, min(m3, m5));
            if (mn == m2) ++i2;
            if (mn == m3) ++i3;
            if (mn == m5) ++i5;
            res.push_back(mn);
        }
        return res.back();
    }
};

我们也可以使用最小堆来做,首先放进去一个1,然后从1遍历到n,每次取出堆顶元素,为了确保没有重复数字,进行一次 while 循环,将此时和堆顶元素相同的都取出来,然后分别将这个取出的数字乘以 2,3,5,并分别加入最小堆。这样最终 for 循环退出后,堆顶元素就是所求的第n个丑陋数,参见代码如下:

解法二:

class Solution {
public:
    int nthUglyNumber(int n) {
        priority_queue<long, vector<long>, greater<long>> pq;
        pq.push(1);
        for (long i = 1; i < n; ++i) {
            long t = pq.top(); pq.pop();
            while (!pq.empty() && pq.top() == t) {
                t = pq.top(); pq.pop();
            }
            pq.push(t * 2);
            pq.push(t * 3);
            pq.push(t * 5);
        }
        return pq.top();
    }
};

原文地址:https://www.cnblogs.com/wwj99/p/12262866.html

时间: 2024-11-08 09:52:45

LeetCode——264. 丑数 II的相关文章

Leetcode 264.丑数II

丑数II 编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n = 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数. 说明:  1 是丑数. n 不超过1690. 思路:动态规划思想.后面的丑数一定是由前面的丑数乘以2.3或5得到.所以第n个丑数一定是由前n-1个数中的某3个丑数(分别记为index2.index3.index5)分别乘以2.3或者5得到的数中的最小数,index2,

Leetcode之动态规划(DP)专题-264. 丑数 II(Ugly Number II)

编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n = 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数. 说明: 1 是丑数. n 不超过1690. dp含义: dp[i]表示第i-1个丑数. class Solution { public int nthUglyNumber(int n) { int[] dp = new int[n + 1]; dp[0] = 1; int i2

264丑数II

题目: 来源: 法一:自己的超时代码 思路:从2开始由小到大遍历判断每一个数是否为丑数,由于到后面丑数越来越稀疏,导致非常费时间. class Solution: def nthUglyNumber(self, n: int) -> int: if n == 1: return 1 ans = [1] k = 2 while len(ans) < n: for j in [2,3,5]: # 如果除以2 3 5中的某个数可以除尽,则判断商是否在之前的数中 # 如果在说明是丑数,否则不是 if

264. 丑数 II

1 //动态方程dp[i]=min(dp[p_2]*2,dp[p_3]*3,dp[p_5]*5) 2 class Solution 3 { 4 public: 5 int nthUglyNumber(int n) 6 { 7 vector<int> dp(n); 8 dp[0] = 1; 9 int p2,p3,p5; 10 p2 = p3 = p5 = 0; 11 for (int i = 1;i < n;++ i) 12 { 13 dp[i] = min(2 * dp[p2],min

leetcode 丑数 II java

题目: 编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n = 10输出: 12解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数.说明: 1 是丑数.n 不超过1690. 解题: 使用三指针 class Solution { public int nthUglyNumber(int n) { int min2 = 0; int min3 = 0; int min5 = 0; int []result =

LeetCode(264):Ugly Number II

Ugly Number II:Write a program to find the n-th ugly number.Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.Note that 1 is typically

[Swift]LeetCode264.丑数 II | Ugly Number II

Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. Example: Input: n = 10 Output: 12 Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers. Note

(medium)LeetCode 264.Ugly Number II

Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers. Note that 1 is typically treated as an

[LeetCode]70. Ugly Number II第N个丑数

Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers. Note that 1 is typically treated as an