筆試題--求幸運數個數

題目描述:
定義一個函數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,若當前數字不是幸運數,那當前幸運數個數與它前一個數字的幸運數個數相等。

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