C++ 查找不在1和10000000之间的丑陋数字

C++ 查找不在1和10000000之间的丑陋数字,c++,C++,我在试图找出那个不难看的数字时遇到了一些问题。 丑陋的数字是唯一的素数为2、3或5的数字。那么,不丑陋的数字呢? 我试图找出介于1和100000000之间的不难看的数字。我的程序可以解决这个问题,但似乎有点慢。如何使它更快? 代码如下: #include <iostream> #include <queue> using namespace std; typedef pair<unsigned long,int> node_type; main() {

我在试图找出那个不难看的数字时遇到了一些问题。 丑陋的数字是唯一的素数为2、3或5的数字。那么,不丑陋的数字呢? 我试图找出介于1和100000000之间的不难看的数字。我的程序可以解决这个问题,但似乎有点慢。如何使它更快? 代码如下:

#include <iostream>
#include <queue>
using namespace std;
typedef pair<unsigned long,int> node_type;
main()
{
    //generates 1500 ugly numbers into result[];
    unsigned long result[1500];
    priority_queue<node_type,vector<node_type>,greater<node_type> > Q;
    Q.push(node_type(1,2));
    for(int i=0;i<1500;i++)
    {
        node_type node = Q.top();
        Q.pop();
    switch(node.second)
    {
        case 2:Q.push(make_pair(node.first*2,2));
        case 3:Q.push(make_pair(node.first*3,3));
        case 5:Q.push(make_pair(node.first*5,5)); 
    }
    result[i]=node.first;
}
/*****************************************************
//Here is the approach I used:
//The initial value of the integer k is 1;
//and will increase by 1 every time 
//k will be checked if it's a ugly number,if not increase by 1,keep doing
//this till k is not a ugly number,then count how much ugly number(we may 
//call it n) is less the the
//current value of k.The result of (k-n) is the order number of this (k) not ugly
//for example:the 1st not ugly number is 7.
// there are 6 ugly number less than 7,which are 1 2 3 4 5 6,
// k=1-->k==2-->.....k=7, k-n=7-6=1,so 7 is the 1st not ugly number
***************************************************************/
int T;  // The amount of cases
cin>>T;
while(T--)
{
    int n;
    int k=0,i=0,count=0;
    cin>>n;

    while(n)
    {
        if((k+1)==result[i]) {k++;i++;count++;}
        else 
        {
            k++;
            if(k-count==n) {cout<<k<<endl;break;}
        }
    }
}}
#包括
#包括
使用名称空间std;
typedef对节点\ u类型;
main()
{
//将1500个丑陋的数字生成结果[];
无符号长结果[1500];
优先级队列Q;
Q.push(节点_型(1,2));

对于(inti=0;i理解代码,我知道您真正想要的是快速找到 第n个非丑陋数字

你找到第n个非丑数的算法是O(n),你可以用二进制搜索找到它们,它是O(log(n))

有T种情况,如果T很大,我的方法可以节省很多时间

这是我的密码,换成你的

#include <iostream>
#include <queue>
using namespace std;
typedef pair<unsigned long,int> node_type;
int main()
{
    //generates 1500 ugly numbers into result[];
    unsigned long result[1500];
    priority_queue<node_type,vector<node_type>,greater<node_type> > Q;
    Q.push(node_type(1,2));
    for(int i=0;i<1500;i++)
    {
        node_type node = Q.top();
        Q.pop();
        switch(node.second)
        {
            case 2:Q.push(make_pair(node.first*2,2));
            case 3:Q.push(make_pair(node.first*3,3));
            case 5:Q.push(make_pair(node.first*5,5));
        }
        result[i]=node.first;
    }

    int T;  // The amount of cases
    cin>>T;
    //b_search_data[i] mean the count of non ugly number blow or equal i, i start from 1
    unsigned long b_search_data[1501];

    for (int i=0; i<1500; i++)
    {
        b_search_data[i] = result[i] - i - 1;
    }
    vector<int> search_data(b_search_data, b_search_data+1500);
    while(T--)
    {
        int n;
        int k=0,i=0,count=0;
        cin>>n;
        // use binary search here to find the n-th non ugly number instead your approach
        int position = upper_bound(search_data.begin(), search_data.end(), n-1) - search_data.begin();
        // position means
        cout<<position + n<<endl;
    }
}
#包括
#包括
使用名称空间std;
typedef对节点\ u类型;
int main()
{
//将1500个丑陋的数字生成结果[];
无符号长结果[1500];
优先级队列Q;
Q.push(节点_型(1,2));
对于(int i=0;i>T;
//b_search_data[i]是指非丑陋数字blow或等于i的计数,i从1开始
无符号长b_搜索_数据[1501];
对于(int i=0;i>n;
//在这里使用二进制搜索来查找第n个非丑陋数字,而不是您的方法
int position=上限(search_data.begin(),search_data.end(),n-1)-search_data.begin();
//职位意味着

cout好吧,我咬一口。根据这个定义,测试一个数字是否丑陋实际上在计算上相当简单。用暴力测试1亿个数字

#include <iostream>

bool is_ugly(unsigned n) {
  while(n % 5 == 0) n /= 5;
  while(n % 3 == 0) n /= 3;
  while(n % 2 == 0) n /= 2;

  return n == 1;
}

int main() {
  unsigned counter = 0;
  for(unsigned i = 1; i <= 100000000; ++i) {
    if(!is_ugly(i)) {
      ++counter;
    }
  }

  std::cout << counter << std::endl;
}
这个报告回来了,嗯

$ time ./a.out 
1105

real    0m0.001s
user    0m0.000s
sys     0m0.000s
你可以使用这个函数,希望
num.find(n)=num.end()
is_丑陋(n)
(使用以前的
is_丑陋
函数)更快地测试非丑陋性,但在我的基准测试中,差异可以忽略不计,而使用
std::unordered_set
实际上要慢2-3倍

附录:可以节省一些时间的是将丑陋的数字生成一个
std::vector
,包含1亿个元素,如下所示:

// num is to have the wanted size in advance and be full of false
void generate_uglies(unsigned n, std::vector<bool> &num) {
  if(n < num.size() && !num[n]) {
    num[n] = true;
    generate_uglies(n * 2, num);
    generate_uglies(n * 3, num);
    generate_uglies(n * 5, num);
  }
}
//num是预先拥有想要的大小,并且充满false
void generate_uglies(无符号n,std::vector&num){
如果(n
然后用
!num[i]
测试非难看的数字。
!num[i]
测试比
是难看的
函数快得多(对于平均低于1亿的值,测试速度是~5倍)1.出于上述原因,如果要打印它们,这并不重要,但在不同的上下文中,这可能会产生明显的差异。请注意,此表需要12.5 MB RAM


1由于您的机器不是我的,因此您的里程数会有所不同。我使用的是一台1.5年的i7。

生成难看的数字可以通过递归函数实现

实际上,如果
N
是丑陋的,那么
2*N
3*N
5*N
也是丑陋的

实际上,
2*N
3*N
5*N
都是丑陋的数字大于N,因此您可以确定一个最大值,比如说
MAX
,并通过添加
2*N
3*N
5*N
(这是递归部分)来查看比
N
更丑陋的数字

为了停止重复搜索,我们可以将所有找到的数字存储在一组丑陋的数字中,因此,例如,当我们得到6作为
3*2
的乘积时,当我们找到
2*3
时,我们不添加它(并研究它所有丑陋的后代)(也等于6--我们称之为冲突)

该计划最终将实现:

#include <cstdio>
#include <set>

using namespace std;

const unsigned N = 10000000;

set<unsigned> uglys;
unsigned n_collis = 0;


void srch_ugly(unsigned n)
{
    if (uglys.find(n) != uglys.end()) { /* found in set */
        ++n_collis;
    } else {
        uglys.insert(n);
        if (2*n < N) srch_ugly(2*n);
        if (3*n < N) srch_ugly(3*n);
        if (5*n < N) srch_ugly(5*n);
    } /* if */
} /* srch_ugly(unsigned) */

int main()
{
    unsigned col = 0; /* printing column */

    srch_ugly(1);

    /* print results */    
    printf("%lu uglys.  %u collissions.\n", uglys.size(), n_collis);
    for (set<unsigned>::iterator i = uglys.begin();
            i != uglys.end();
            ++i)
    {
        if (col >= 72) {
            puts("");
            col = 0;
        } /* if */
        col += printf("%s%i", col ? " " : "", *i);
    } /* for */
    if (col) puts("");
} /* main */
#包括
#包括
使用名称空间std;
常数无符号N=10000000;
设置uglys;
无符号n_collis=0;
void srch_丑陋(未签名n)
{
如果(uglys.find(n)!=uglys.end()){/*在集合中找到*/
++n_collis;
}否则{
uglys.插入(n);
如果(2*n=72){
认沽权(“”);
col=0;
}/*如果*/
col+=printf(“%s%i”,col?”:“”,*i);
}/*用于*/
若(col)以(“”)号填列;
}/*主要*/

很抱歉使用了
printf
stdio函数,但我想在72个字符处剪切行,而
printf
函数返回打印的字符数(我不知道如何从
ostream
类中获取实际打印的字符数),所以我使用了它们。

定义“更快”?需要多快?现在有多快?这个问题可能更适合。它甚至不编译。我希望至少有一个名为isught()的函数;你实际上需要做什么?找到所有不难看的数字,或者确定某个特定的数字是否难看?你说你需要前者,但从你的代码来看,你实际上需要后者。两个词:。你有多少可用内存?是的,你希望它有多快?谢谢你的回答!我花了很多时间才弄明白站起来,因为我只是一个初学者……不管怎样,我从你的分析中学到了很多。:)很好的解决方案!我也在考虑使用二进制搜索来找到答案,但我不知道怎么做……你告诉我在这个问题中使用二进制搜索的方法。谢谢!
#include <cstdio>
#include <set>

using namespace std;

const unsigned N = 10000000;

set<unsigned> uglys;
unsigned n_collis = 0;


void srch_ugly(unsigned n)
{
    if (uglys.find(n) != uglys.end()) { /* found in set */
        ++n_collis;
    } else {
        uglys.insert(n);
        if (2*n < N) srch_ugly(2*n);
        if (3*n < N) srch_ugly(3*n);
        if (5*n < N) srch_ugly(5*n);
    } /* if */
} /* srch_ugly(unsigned) */

int main()
{
    unsigned col = 0; /* printing column */

    srch_ugly(1);

    /* print results */    
    printf("%lu uglys.  %u collissions.\n", uglys.size(), n_collis);
    for (set<unsigned>::iterator i = uglys.begin();
            i != uglys.end();
            ++i)
    {
        if (col >= 72) {
            puts("");
            col = 0;
        } /* if */
        col += printf("%s%i", col ? " " : "", *i);
    } /* for */
    if (col) puts("");
} /* main */