笔试题--求幸运数个数

题目描述:
定义一个函数f(x)表示x这个数用十进制写出各个数位的数字之和,比如:f(123) = 1 + 2 + 3 = 6;定义一个函数g(x)表示这个数用二进制写出各个位数上的数字之和,比如:123用二进制表示为1111011,那么g(1111011) = 1 + 1 + 1 + 1 + 0 + 1 + 1 = 6。若有一个数x有f(x) = g(x),则说明这个数是幸运数。若给定一个范围n,求小于等于n的幸运数有多少个。
输入:第一行一个整数T(T<=10000)表示数据组数,每组数据输入一个数n(n <= 100000)。
输出:每组数据输出一行,小于等于n的幸运数个数。
样例输入:
3
1
5
21
样例输出:
1
1
3
我写的程序如下:

#include <iostream>

using namespace std;

int f(int n)
{
    int sum = 0;
    while(n)
    {
        sum += n % 10;
        n /= 10;
    }
    return sum;
}

int g(int n)
{
    int sum = 0;
    while(n)
    {
        sum ++;
        n = n % (n - 1);
    }
    return sum;
}

int main(void)
{
    int T;
    while (cin >> T)
    {
        while (T--)
        {
            int n;
            cin >> n;
            int cnt = 0;
            for (int i = 1; i <= n; ++i)
            {
                if (f(i) == g(i))
                    cnt ++;
            }
            cout << cnt << endl;
        }
    }
    return 0;
}

可是将这种暴力做法上传上去发现,用例一个都没跑出来,运行超时。
下来之后,上网查还有没有更好的方法,看到网友的讨论说这样暴力做法重复的运算太多了,如果将运算后的结果保存下来,就大大节省了时间,说的好有道理。算法修改为先一口气算完1~100000所有的数的幸运数,之后每次输入一个数,直接查找数组即可获得答案。算法修改如下:

#include <iostream>
#include <vector>

using namespace std;

int f(int n)
{
    int sum = 0;
    while(n)
    {
        sum += n % 10;
        n /= 10;
    }
    return sum;
}

int g(int n)
{
    int sum = 0;
    while(n)
    {
        sum ++;
        n = n & (n - 1);
    }
    return sum;
}

int main(void)
{
    vector<unsigned long long> ans(100001, 0);
    for (unsigned int i = 1; i < 100001; ++i)
    {
        if (f(i) == g(i))
        {
            ans[i] = 1 + ans[i - 1];
        }
        else
        {
            ans[i] = ans[i - 1];
        }
    }
    int T;
    while (cin >> T)
    {
        int n;
        while (T--)
        {
            cin >> n;
            cout << ans[n] << endl;
        }
    }
        return 0;
}

定义的一个ans数组,用来存放1~100000所有数字从1到该数字的幸运数个数,之后直接从ans数组中取出答案。逻辑是:若当前数字是幸运数,那它前边的总幸运数加1,若当前数字不是幸运数,那当前幸运数个数与它前一个数字的幸运数个数相等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章