編程之美 - 尋找合適的數字

問題描述:

給一個整數N,求一個整數M,使M*N 的十進制結果中只有 1 和 0。

問題分析:

問題從結果入手,十進制表示只有 1 和 0,這個數字的集合有規律,例如: 1,10,11,100,101,110,111.....
10k次方與前面的每個的數的和。
例如 k=1  ==> 10 ,在 10這個階段的數字有 1 + 10 = 11
例如 k=2  ==> 100 ,在 100這個階段的數字有 1 + 100 = 101, 10+100=110,11+100=111

方式1: 從1開始,嘗試每一個1,0組合的結果Result,找到 Result % N == 0的Result,再用 Result / N就得到M。
可以做到,但效率不高。

方式2:每個數字的遍歷會比較浪費時間,書中用餘數的方式進行考慮。
假設最後的乘積爲X,X有可能是10的k次方,也有可能是10的k次方與有效數集合中之前一個數的和,
假設 X = 10^k + Y,Y也滿足只有0和1組成,類似於 111 = 100 + 11。如果X是期望的結果,那麼 一定有(10^k % N + Y % N) == N

可以定義一個大小爲N的數組(X%N的餘數的範圍是從1~N-1),用來保存X的值的餘數。
如果數組中兩個數組下標(這裏的數組下標就是餘數)的和爲N,並且兩個元素都有效,那最後的結果就是這兩個元素的和。

用數字3舉例  N = 3,   餘數數組  mod_list[3+1]  定義有 3+1個元素,方便計算

k = 0     X = 1       mod 3 = 1    mod_list[1]  =  1
k = 1     X = 10     mod 3 = 1   因爲 mod_list[1]  =  1 已經存在了,所以不用改變。
             推導出  mod_list[1+1]  =  11   即 11%3=2   mod_list[2] = 11
k = 2     X = 100   mod 3 = 1,這時 mod_list[2] 已經存在了,而且 2+1=3
那最後的結果就是   100 + mod_list[2] = 100 + 11 = 111

這種方式是 3次取模,一次加法運算。

如果用遍歷的方式則需要遍歷(1, 10, 11, 100, 101, 110, 111) 7個數字,7次取模。2^k - 1次

#include <iostream>
#include <vector>

using namespace std;

int find2(int num)
{
    int result = 0, k = 0, step = 1;
    int i = 0, j = 0, curr = 0;
    bool exist = false;
    int* plist = new int[num+1];
    vector<int> list;
    memset(plist, 0, sizeof(int)*(num+1));

    while (result == 0)
    {
        k = step % num;
        if (k == 0)
        {
            result = step;
        }
        else if (plist[num-k] != 0)
        {
            result = plist[num-k] + step;
        } 
        else
        {
            list.clear();
            if (plist[k] == 0)
            {
                list.push_back(k);
                plist[k] = step;
            }
            exist = false;
            for (i = 1; i < num+1; i++)
            {
                curr = (i+k) % num;
                for (j = 0; j < list.size(); j++)
                {
                    if (list[j] == i)
                        exist = true;   // make sure the same value not calculate twice
                }

                if ((plist[i] != 0) && (!exist) && (plist[curr] == 0))
                {
                    list.push_back(curr);
                    plist[curr] = step + plist[i];
                }
            }
        }
        step *= 10;
    }

    cout << num << " * " << result/num << " = " << result << endl << endl;

    delete[] plist;
    plist = NULL;
    return result;
}

int find(int num)
{
    int result = 0;
    int step = 10, i = 0, curr = 0, cnt = 0;
    vector<int> list;

    list.push_back(1);

    while(list[curr]%num != 0)
    {
        if (curr == list.size()-1)
        {
            list.push_back(step);
            cnt = list.size() - 1;
            for (i = 0; i < cnt; i++)
                list.push_back(list[i]+step);
            step *= 10;
        }
        curr++;
    }
    result = list[curr];
    cout << num << " * " << list[curr]/num << " = " << list[curr] << endl << endl;
    return result;
}

void main()
{
    int test[] = {5, 12, 11, 6, 9, 21, 30};
    int len = sizeof(test)/sizeof(test[0]);
    int i = 0; 

    for (i = 0; i < len; i++)
        find(test[i]);
    cout << "\n\n=======================================\n" <<endl;
    for (i = 0; i < len; i++)
        find2(test[i]);
    cin >> i;
}



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