2013-11-01 29 views
1

我有三個整數變量,可以只取值0,12。我想區分我擁有的所有三個數字的組合,排序不計算在內。假設這些變量被稱爲x,yz。那麼x=1, y=0, z=0x=0, y=1, z=0x=0, y=0, z=1在這種情況下都是相同的數字,我將這個組合稱爲001區分三個int的值

現在有一百種方法可以做到這一點,但我要求一個優雅的解決方案,無論是爲了教育目的。

我想過按位由價值的金額轉移001

001 << 0 = 1 
001 << 1 = 2 
001 << 2 = 4 

但隨後的數002111既能給6

+0

只是爲了澄清,你有三個變量要存儲0,1或2嗎?用戶可以輸入001/010/100爲1,可以輸入002/020/200爲2? – Steven

+0

我會在正文中予以澄清。 – pfnuesel

+0

'001'和'110'是否一樣? – dasblinkenlight

回答

7

的轉變想法是好的,但你需要位計數3。因此,嘗試通過兩次移位的位數:

1 << (2*0) = 1 
1 << (2*1) = 4 
1 << (2*2) = 16 

添加這些所有的3號和第2位將算多少0你哈ve,第二個2位會計算多少1和第三個2位會計算多少個2

編輯雖然結果是6位長,你只需要低4位的唯一標識符(每個號碼選項0,1,2 2位) - 因爲如果你知道你有多少01有,那麼也確定2的數目。的

所以與其做

res = 1<<(2*x); 
res+= 1<<(2*y); 
res+= 1<<(2*z); 

你可以做

res = x*x; 
res+= y*y; 
res+= z*z; 

因爲那時

0*0 = 0 // doesn't change result. We don't count 0 
1*1 = 1 // we count the number of 1 in the 2 lower bits 
2*2 = 4 // we count the number of 2 in the 2 higher bits 

因此可以僅通過4位而不是6

1

對於這樣小的數字,這將是最簡單的只是檢查他們的個人,而不是試圖將花式,如:

bool hasZero = false; 
bool hasOne = false; 
bool hasTwo = false; 

// given: char* number or char[] number... 

for(int i = 0; i < 3; ++i) 
{ 
    switch (number[i]) 
    { 
     case '0': hasZero = true; break; 
     case '1': hasOne = true; break; 
     case '2': hasTwo = true; break; 
     default: /* error! */ break; 
    } 
} 
1

如果我沒有理解你正確的,你有一些數字序列,可以是1,2或3,其排列順序不重要(只是不同的組合)。

既然如此:

std::vector<int> v{1, 2, 3}; 
std::sort(v.begin(), v.end()); 

這將讓所有正確對齊的不同的組合,你可以很容易地寫一個循環來測試相等。

或者,您可以使用std::array<int, N>(其中N是可能值的數量 - 在本例中爲3)。

std::array<int, 3> a; 

在這裏您將設置a[0]等於你有1 S上的號碼,a[1]等於「2的數量等

// if your string is 111 
a[0] = 3; 

// if your string is 110 or 011 
a[0] = 2; 

// if your string is 100 or 010 or 001 
a[0] = 1; 

// if your string is 120 
a[0] = 1; 
a[1] = 1; 

// if your string is 123 
a[0] = 1; 
a[1] = 1; 
a[2] = 1; 

如果您正在尋找將其存儲在一個單一的32位整數:

unsigned long x = 1; // number of 1's in your string 
unsigned long y = 1; // number of 2's in your string 
unsigned long z = 1; // number of 3's in your string 
unsigned long result = x | y << 8 | z << 16; 

檢索每個數,你會做

unsigned long x = result & 0x000000FF; 
unsigned long y = (result >> 8) & 0x000000FF; 
unsigned long z = (result >> 16) & 0x000000FF; 

這與宏在RBG中發生的情況非常相似。

4

當不同可能性的數量很小時,可以使用查找表。

首先,號碼的三位數字的所有可能的組合,例如:

Combinations     N  Indexes 
-------------     -  ------ 
000       0  0 
001, 010, 100     1  1, 3, 9 
002, 020, 200     2  2, 6, 18 
011, 101, 110     3  4, 10, 12 
012, 021, 102, 120, 201, 210 4  5, 7, 11, 15, 19, 21 
022, 202, 220     5  8, 20, 24 
111       6  13 
112, 121, 211     7  14, 16, 22 
122, 212, 221     8  17, 23, 25 
222       9  26 

第一列顯示相同的組合;第二欄顯示組合的編號(我將它們任意分配);第三欄顯示每個組合的索引,計算結果爲9*<first digit> + 3*<second digit> + <third digit>

接下來,建立一個查找表中的每個這十個組合,用這種表達作爲指標:

9*a + 3*b + c 

其中ab,並c是你有三個數字。該表是這樣的:

int lookup[] = { 
    0, 1, 2, 1, 3, 4, 2, 4, 5, 1 
, 3, 4, 3, 6, 7, 4, 7, 8, 2, 4 
, 5, 4, 7, 8, 5, 8, 9 
}; 

這是第一個表的改寫,在對應於該值在列N索引值。例如,在索引1,39中找到組合號1;組合2在索引2,618等等。

爲了獲得組合的號碼,只需檢查

int combNumber = lookup[9*a + 3*b + c]; 
+0

我喜歡你的方法,但不是N = 4和N = 8不可區分組合的情況嗎? – Matt

+0

@Matt是的,你是絕對正確的!感謝您指出這一點,我改變了表來解決這個問題。 – dasblinkenlight

1
int n[3]={0,0,0}; 
++n[x]; 
++n[y]; 
++n[z]; 

現在,N排列中,你有值的X,Y,Z的每一個獨特的無序組合的唯一有序組合。

例如,兩個X = 1,Y = 0,Z = 0和x = 0,Y = 0,Z = 1會給你N = {2,1,0}