Leetcode--263,264--丑数I II

萌新一枚、个人记录~多多指教
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ugly-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目描述263

编写一个程序判断给定的数是否为丑数。
丑数就是只包含质因数 2, 3, 5 的正整数。

示例 1:           示例 2:               示例 3:      
输入: 6           输入: 8               输入: 14
输出: true        输出: true            输出: false 
解释: 6 = 2 × 3   解释: 8 = 2 × 2 × 2   解释: 14 不是丑数,因为它包含了另外一个质因数 7

说明:
1 是丑数。
输入不会超过 32 位有符号整数的范围: [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [231,2311]

思路

分析题意,丑数的条件是:

  • 正整数
  • 质因数只含有2,3,5
  • 1也是丑数

此题较为简单,只需要判断 是否是丑数。对这几个数进行取模然后再除以这几个数,直到最后为1即是丑数。如果对这个几个数取模都不能整除那一定不是丑数,所以使用else if,一直连续判断,如果除以2,3,5,都除不尽那就是丑数。

  class Solution {
public:
    bool isUgly(int num) {
        if(num<=0) return false; // 条件1
        while(num!=1) // 以下是判断条件2
        {
            if(num%2==0) num/=2; 
            else if(num%3==0) num/=3;
            else if(num%5==0) num/=5; 
            else return false;
        }
        return true;//条件3
    }
};

题目描述264

编写一个程序,找出第 n 个丑数。
丑数就是只包含质因数 2, 3, 5 的正整数。

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

说明:
1 是丑数。
n 不超过1690。

思路

暴力解法
利用三层循环找出n个丑数,放入vector中,再利用sort函数排序(默认就是从小到大),然后输出最后一个丑数
(相当于预计算了前n 个丑数)
以下为自己测试的代码。

#include <iostream>
#include <vector> 
#include <algorithm> //sort函数头文件

using namespace std;

int main()
{
    int n;
    cin >> 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());

    cout << v.at(n-1) <<endl; //当像数组下标一样索引vector中一个元素时,并没有检查索引值,所以当索引可能越界时,应该通过 at() 函数去使用这个元素。
    return 0;
}

优先队列思想

利用优先队列的自动排序特点
将数据放入优先队列中,利用他有排序的功能,可以减少一部分的复杂度,只需要计算前n个丑数,第n个丑数已经到了队首。这里并没有把1,放进去因此第n个丑数对应的是我们算出来的第n-1个数,这里注意细节。
但注意去重,q中可能有重复的元素,注意重复几次就删除几次

#include <iostream>
#include <queue>
#include <iomanip> //控制测试时的输出格式,在测试1690时,由于数据特别大会显示为指数形式,不明了

//利用优先队列完成
//输出第n 个丑数,n由你输入
using namespace std;

int main()
{
    int n;
    cin>>n;

    priority_queue <double,vector <double>,greater<double> >p;
    double ans=1;

    for(int i=1;i<n;i++) //这里注意1没有放进p中,因此i=n-1时,就是第n个丑数
    {
        //先把乘积都放入p
        p.push(ans*2);
        p.push(ans*3);
        p.push(ans*5);
        //利用它自动排序的特点,更新ans值(第i+1个丑数)
        ans=p.top();
        //删除这个丑数,要排除有重复的情况
        p.pop();
        while(ans==p.top()&&!p.empty())//因为可能不止重复1次,因此不能简单的用if解决!!!
        p.pop();

    }
    cout <<fixed << setprecision(0) << ans <<endl;

    return 0;
}

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);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值