【劍指offer】字串的組合

蘭亭風雨發表於2014-05-21

轉載請註明出處:http://blog.csdn.net/ns_code/article/details/26405471


    劍指offer上的擴充題目,輸入一個字串,輸出該字串的字元的所有組合,比如輸入字串:abc,輸出a、b、c、ab、ac、bc、abc。

    思路:與上一題類似,也可以用遞迴求解。可以考慮求長度為n的字串中m個字元的組合,設為C(n,m)。原問題的解即為C(n, 1), C(n, 2),...C(n, n)的總和。對於求C(n, m),從第一個字元開始掃描,每個字元有兩種情況,要麼被選中,要麼不被選中,如果被選中,遞迴求解C(n-1, m-1)。如果未被選中,遞迴求解C(n-1, m)。不管哪種方式,n的值都會減少,遞迴的終止條件n=0或m=0。

    博主是剛開始嘗試用遞迴去寫,寫了一個多小時都沒寫出來,桑心啊!除了操作二叉樹寫遞迴比較順,其他好多地方用遞迴愣是憋不出來,尤其字串操作。

    在何海濤部落格下看到有人留言,給了個思路,覺得很不錯,自己把程式碼寫了出來。具體思路如下:

    開闢一個於字串對應長度的int陣列(char陣列也可以,而且更節省空間),用該陣列模擬二進位制的加1操作,則該陣列的元素只能為0或1,我們規定如果該陣列某個位置處的元素是1,則字串對應位置處的字元參與組合,如果為0,則字串對應位置處的字元不參與組合,這樣講該int陣列,從全0加到全1,便可得到字串的全部組合。

    這裡沒有去除重複子串,也沒按照字典序輸出,如果要求按照字典序輸出,並去掉重複子串的話,可以採取上道題目一樣的辦法,先將所有的字串儲存在字串陣列中,而後通過快排使陣列中的字串按照字典序排列,再在輸出的時候,跳過重複的字串。

    實現程式碼如下:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

/*
模擬二進位制加1操作,當最高位要進位時,說明所有的位都是1,返回false,
用char陣列來模擬比int陣列更省空間,這裡必須傳入陣列長度len,
由於我們CominationAll中將要傳入的字元陣列全部初始化為了'\0',
如果在該函式內部用strlen計算的話,會得到len=0。
*/
bool Increment(char *BindAdd,int len)
{
	if(BindAdd == NULL)
		return false;

	BindAdd[len-1]++;
	int i;
	for(i=len-1;i>=0;i--)
	{
		if(BindAdd[i] >= 2)
		{
			if(i == 0)
			{
				BindAdd[i]--;
				return false;
			}
			else
			{
				BindAdd[i] -= 2;
				BindAdd[i-1]++;
			}
		}
		else
			break;
	}
	return true;
}

/*
輸出字串的所有組合
*/
void CominationAll(char *str)
{
	if(str == NULL)
		return;

	int len = strlen(str);
	char *BindAdd = (char *)malloc(len*sizeof(char));
	if(BindAdd == NULL)
		exit(EXIT_FAILURE);

	memset(BindAdd,0,len*sizeof(char));
	while(Increment(BindAdd,len))
	{
		int i;
		for(i=0;i<len;i++)
		{
			if(BindAdd[i] == 1)
				putchar(str[i]);
		}
		putchar('\n');
	}

	free(BindAdd);
	BindAdd = NULL;
}

int main()
{
	char str[10];
	while(gets(str))
		CominationAll(str);
	return 0;
}
    測試結果:



相關文章