萌新一枚、个人记录~多多指教
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ugly-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
编写一个程序判断给定的数是否为丑数。
丑数就是只包含质因数 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,231−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
}
};
编写一个程序,找出第 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
#include
#include //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
#include
#include //控制测试时的输出格式,在测试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);
}
};