2012-01-29 105 views
8

我試圖有效地列出1和100之間的數字。但是我必須擺脫具有相同數字的數字。
實施例: 12根據該規則是相同的21 13是31 14是41 所以for循環也不會越過相同的數字。
我在想一些技巧,比如從1到100的所有數字,然後刪除找到的當前編號的排列。 我問這個的原因是因爲像100000這樣的大限制會失敗。 又如: 124等於142,241,214,412,421C++中的唯一編號

+2

你爲什麼要得到相同的數字擺脫數字的?這是一個家庭作業問題嗎? – 2012-01-29 20:52:14

+0

這裏有問題嗎? – talonmies 2012-01-29 20:53:09

+0

看起來像一個家庭作業。你有什麼問題編寫代碼? – bratao 2012-01-29 20:54:49

回答

6

您可以申請遞歸。這個函數的原型是那麼喜歡:

print_digits(int num_of_remaining_digits,int start_from_digit, int current_number); 

編輯:完成我在這裏我的解決方案(我認爲這不是從本福格特和升輸出順序

void print_digits(int num_of_remaining_digits,int start_from_digit, int current_number) 
{ 
    if(num_of_remaining_digits == 0) 
    { 
    std::cout << current_number << std::endl; 
    return; 
    } 

    for(int i=start_from_digit;i<=9;i++) 
    { 
    print_digits(num_of_remaining_digits-1,i,10*current_number+i); 
    } 
} 

更好readbility這裏是測試代碼

http://ideone.com/Xm8Mv

這是如何工作的?

它是遞歸中的經典之一。首先有停止條件。然後是主循環。
主循環從start_from_digit開始,因爲所有生成的數字都將以非遞減順序排列。舉例來說,如果current_number15它會調用print_digits蒙山

print_digits(num_of_remaining_digits-1,5,155) 
print_digits(num_of_remaining_digits-1,6,156) 
print_digits(num_of_remaining_digits-1,7,157) 
print_digits(num_of_remaining_digits-1,8,158) 
print_digits(num_of_remaining_digits-1,9,159) 

在每一個調用它會檢查,如果我們達到最終白衣num_of_remaining_digits,如果不繼續使用該被推爲start_from_digit(第二PARAM)位數current_number

+0

不可思議!謝謝。正是我所需要的 – Ali 2012-01-29 21:47:26

+0

你能否詳細解釋一下我? – Ali 2012-01-29 21:49:24

+1

當問題被標記爲「performance」時,最好遠離'std :: cout'。否則一個很好的解 – 2012-01-29 21:51:00

0

好像它可以這樣簡單:

list = {} 
for (j = 1 to 100) 
    if (j is not excluded from list) 
      list += j; 

真的,只有if條件有趣的是:需要檢查列表的所有相關屬性項目。

1

我會通過超載正確的操作員(從我的頭頂應該只是less)和std::set來寫一個適合您比較需求的課程。

0

創建一個函數,該函數接受一個字符串,並返回一個字符串數組,其中包含該字符串中字符的所有可能排列組合。這並不難,但它可能是最簡單的遞歸。雖然說起來容易做起來難。

一旦你有了這個函數,並且它返回數組,你只需要遍歷數組並刪除與數組中的一個共享數的indecies。

+0

感謝您的回答。我遇到的麻煩是,當我嘗試應用這種方法時,上限大於等於5000萬時,算法運行起來很慢。我試過在循環中不做任何事情,但增加了一個參數,但即使這樣也會花費10秒以上。 – Ali 2012-01-29 20:57:48

+0

然後你有一個問題,因爲這是測試每個可能的排列的唯一合理的方法。 – Zyerah 2012-01-30 01:36:25

1

我會用一個散列表,像這樣

1)從派生的數字中派生出一個密鑰,使得具有相同數字的數字具有相同的密鑰(例如總和數字,所以「124」和「142」有關鍵7,或拿(+1)的乘積,因此「124」和「142」具有密鑰30-必須對數字+1 +1)

2)將數字放入由密鑰

索引的散列表中

現在,關於您是否已經擁有數字相同的數字的測試僅限於散列表中具有相同鍵的實體。這種算法需要線性存儲,其性能取決於您可以提供多少密鑰。

1

首先,觀察你的規則與第一個數字= 1

生成所有2位數字不包括11(爲什麼?)

開始倍數現在,生成所有2位數第一個數字= 2,但不生成任何與第一個列表中的數字匹配的數字。

重複3,但不要從前兩個列表中生成任何數字。

請注意,對於任何2位數的數字ab,如果符合條件,則必須是< b,否則您已經生成了相應的數字ba。

在PASCAL語言中,只是因爲我覺得一文不值:

var i:integer; j:integer; 
begin 
    for i := 1 to 8 do 
    for j := i+1 to 9 do 
     println(i*10+j); 
end; 

增加了稍晚

注意要生成的數字總是有自己的數字嚴格單調遞增。對於數字2abc資格,觀察2 < a < b < c。 (實施例:2539是一個匹配2359,並應被拒絕。)

+0

相同的數字a Ali 2012-01-29 21:10:01

0

我會使用一個set爲的號碼的數字的置換:

std::vector<int> list_unwanted = digit_permutations(number); 
std::unordered_set<int> set_unwanted(begin(list_unwanted), end(list_unwanted)); 

然後循環從0到極限,通過檢查增加不必要的數字,如果他們在集合set_unwanted

std::vector<int> numbers; 
numbers.reserve(limit - set_unwanted.count()); 

for (int i = 0; i < limit; ++i) 
    if (!set_unwanted.count(i)) 
0

如果你有一組數字,這組的任何排列是不是一個有效的解決方案,所以首先進行功能如果一組數字是另一組的排列,則確定R集。 要獲得單個數字,您可以遞歸地除以10,直到獲得零值。 如果你把所有的數字像[1,2,4]數組,以檢查是否antoher陣列是antoher集的置換(你選擇了它,只有當他們具有相同的長度):

bool permutation(int *a, int *b, int n) // n leading dimension 
{ 
    bool result=true, vector[n]={false}; 
    for(int i=0;i<n;i++) 
    { 
     for(int j=0;j<n ;j++) 
     { 
      if(a[i]==b[j]) 
       vector[i]=false; 
     } 
    } 
    for(int i=0;i<n && result;i++) 
     result=(vector[i]==true); // if vector[i] is false, result is false, is 
            // not a permutation and the loop ends 
    return result; 
} 

我沒有測試過,但我認爲它有效,否則告訴我。 至於把所有的數字放在一個數組中,我認爲這很容易。 一旦生成所有數字,您檢查確定的數字不是一個已經採取的數字的排列。

+0

如果我不明白錯誤,它適用,就好像一個數字是預填的數字的排列組合。謝謝你的貢獻,但我更喜歡不**不尋找未來的數字。如果發現號碼124發現循環**不應該再次超過241,214。 – Ali 2012-01-29 21:17:42

+0

我意識到這是錯誤的,如果我有一個數組[1,1,1]和[1,2,3],這個函數返回true。 – 2012-01-29 21:23:39

1
#include <stdio.h> 

size_t enum_canonical(char* begin, char* end, char min, char max) 
{ 
    if (begin == end) { 
     puts(begin); 
     putchar('\n'); 
     return 1; 
    } 

    size_t result_count = 0; 
    --end; 
    for(*end = min; *end <= max; ++*end) 
     result_count += enum_canonical(begin, end, min, *end); 

    return result_count; 
} 

int main(void) 
{ 
    char buff[7]; 
    printf("%d results\n", enum_canonical(buff, &(buff[6] = '\0'), '0', '9')); 
} 

演示:http://ideone.com/BWGdg

+0

非常感謝您的幫助。 – Ali 2012-01-29 21:23:02

+0

@rolandbishop:請注意,這與[ralu]提到的方法(http://stackoverflow.com/a/9056758/103167)完全相同。 – 2012-01-29 21:23:58

+0

+1,但仍然這個代碼將運行得像你的一樣快http://ideone.com/RTXqQ :) – 2012-01-29 23:06:47

0

這是我的想法,每個值把它的數字在一組。使用該設置作爲另一組的密鑰,以跟蹤哪些數字已被使用。在我的情況下,我使用位字段作爲數字的集合,即數字0用1表示,數字1用2表示(2等於4等等)。太累了解釋,這裏的塔codez:

unsigned int get_digits(int v) 
{ 
    unsigned int rv = 0; 
    do 
    { 
    rv |= 1 << (v % 10); 
    v /= 10; 
    } while(v); 
    return rv; 
} 

void unique_ints(int n) 
{ 
    std::set<unsigned int> used_combinations; 
    for(int i = 0; i < n; ++i) 
    { 
    const unsigned int d = get_digits(i); 
    if(used_combinations.find(d) == used_combinations.end()) 
    { 
     used_combinations.insert(d); 
     // cout or some other way to store the value 
     std::cout << i << std::endl; 
    } 
    } 
} 
1

讓我們1到1000由於有4位在1000,我打印1爲0001,所以0001,0010,0100,1000是相同數量按我算法。 0120,0012,0210,0102,0201,0021也是相同的數字。

下面是程序:

int main() 
{ 
    int i=0, j=0, k=0; 

    while(i<=9) 
    { 
     int unique=(i*100 + j*10 + k); 
     printf("unique number : %3d\n", unique); 

     if(j==9 && k==9) 
     { 
      i++; 
      k=i; 
      j=i; 
     } 
     else if(k==9) 
     { 
      j++; 
      k=j; 
     } 
     else 
      k++; 
    } 

}