zoukankan      html  css  js  c++  java
  • 【算法01】寻找丑数

      题目:我们把只包含因子235的数称作丑数(Ugly Number)。例如68都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第1500个丑数。

      分析:寻找一个数是不是满足某种数(质数,水仙数)等,最简单的方法就是遍历,对于任意一个丑数必定可以写成2^m*3^n*5^p,因而对于一个丑数,只含有235因子,也就意味着该数number%2==0number%3==0number%5==0,如果一个数能被2整除,我们就连续除以2;能被3整除,我们就连续除以3;能被5整除,我们就连续除以5;如果最后得到1,则该数是素数,否则是丑数。

      代码如下:

     1 #include<iostream>
    2 #include<string>
    3 using namespace std;
    4
    5 //判断一个给定的数number是否是丑数
    6 bool IsUgly(int number)
    7 {
    8 while(number % 2 == 0)
    9 {
    10 number /= 2;
    11 }
    12 while(number % 3 ==0)
    13 {
    14 number /= 3;
    15 }
    16 while(number % 5 ==0)
    17 {
    18 number /= 5;
    19 }
    20 return(number == 1)?true:false;
    21 }
    22
    23 //返回从1开始第index个丑数
    24 int GetUglyNumber(int index)
    25 {
    26 if(index <= 0)
    27 {
    28 return 0;
    29 }
    30
    31 int number=0;
    32 int count=0;
    33 while(count < index)
    34 {
    35 ++number;
    36 if(IsUgly(number))
    37 {
    38 ++count;
    39 }
    40
    41 }
    42
    43 return number;
    44 }
    45
    46 int main()
    47 {
    48 cout<<"Enter A Number:"<<endl;
    49 int idx=0;
    50 cin>>idx;
    51 cout<<GetUglyNumber(idx)<<endl;
    52 return 0;
    53 }

      上面计算中主要的不足在于,逐一遍历,这样对于不是丑数的数的判断会造成大量的时间浪费,如果能够根据已经计算好的丑数,计算出下一个丑数就可以避免这种情况,实现从丑数到丑数的高效算法,根据定义可知,后面的丑数肯定是前面已知丑数乘以235得到的。

      我们假设一个数组中已经有若干丑数,并且这些丑数是按顺序排列的,我们把现有的最大丑数记为max,则下一个丑数肯定是前面丑数乘以235得到的。不妨考虑乘以2得到的情况,我们把数组中的每一个数都乘以2,由于原数组是有序的,因为乘以2后也是有序递增的,这样必然存在一个数M2,它前面的每一个数都是小于等于max,而包括M2在内的后面的数都是大于max的,因为我们还是要保持递增顺序,所以我们取第一个大于max的数M2。同理对于乘以3的情况,可以取第一个大于max的数M3,对于乘以5的情况,可以取第一个大于max的数M5

      最终下一个丑数取:min{M2,M3,M5}即可

      代码如下:

     1 #include<iostream>
    2 #include<string>
    3 using namespace std;
    4
    5 //返回三个数中的最小者
    6 int Min(int number1,int number2,int number3)
    7 {
    8 int min = (number1 < number2) ? number1 : number2;
    9 min = (min < number3) ? min : number3;
    10 return min;
    11 }
    12
    13 //返回第index个丑数
    14 int GetUglyNumber(int index)
    15 {
    16 if(index <= 0)
    17 {
    18 return 0;
    19 }
    20
    21 int *pUglyNumbers = new int[index];
    22 pUglyNumbers[0] = 1;
    23 int nextUglyIndex = 1;
    24
    25 int *pMultiply2 = pUglyNumbers;
    26 int *pMultiply3 = pUglyNumbers;
    27 int *pMultiply5 = pUglyNumbers;
    28
    29 while(nextUglyIndex < index)
    30 {
    31 int min = Min(*pMultiply2 * 2,*pMultiply3 * 3,*pMultiply5 * 5);
    32 pUglyNumbers[nextUglyIndex] = min;
    33
    34 while(*pMultiply2 * 2 <= pUglyNumbers[nextUglyIndex])
    35 {
    36 ++pMultiply2;
    37 }
    38 while(*pMultiply3 * 3 <= pUglyNumbers[nextUglyIndex])
    39 {
    40 ++pMultiply3;
    41 }
    42 while(*pMultiply5 * 5 <= pUglyNumbers[nextUglyIndex])
    43 {
    44 ++pMultiply5;
    45 }
    46
    47 ++nextUglyIndex;
    48 }
    49
    50 int ugly = pUglyNumbers[nextUglyIndex-1];
    51 delete[] pUglyNumbers;
    52 return ugly;
    53
    54 }
    55
    56 int main()
    57 {
    58 cout<<"Enter A number:"<<endl;
    59 int number=0;
    60 cin>>number;
    61 cout<<GetUglyNumber(number)<<endl;
    62 return 0;
    63 }

      第二种方法由于不需要在非丑数的整数花费时间,因而时间复杂度要小很多,在vc6+win7的平台上,index=1500时,方法1的运行时间为40s,方法2的时间是1s;然而方法2需要动态分配内存,占用空间,而方法2则没有这样的内存开销。说白了,第二种方法是用空间换时间。



  • 相关阅读:
    redis发布订阅
    redis学习笔记(面试题)
    redis安全 (error) NOAUTH Authentication required
    HDU3001 Travelling —— 状压DP(三进制)
    POJ3616 Milking Time —— DP
    POJ3186 Treats for the Cows —— DP
    HDU1074 Doing Homework —— 状压DP
    POJ1661 Help Jimmy —— DP
    HDU1260 Tickets —— DP
    HDU1176 免费馅饼 —— DP
  • 原文地址:https://www.cnblogs.com/python27/p/2261550.html
Copyright © 2011-2022 走看看