1. 程式人生 > >演算法-字串全排列問題

演算法-字串全排列問題

轉載地址:http://blog.csdn.net/hackbuteer1/article/details/7462447

全排列在筆試面試中很熱門,因為它難度適中,既可以考察遞迴實現,又能進一步考察非遞迴的實現,便於區分出考生的水平。所以在百度和迅雷的校園招聘以及程式設計師和軟體設計師的考試中都考到了,因此本文對全排列作下總結幫助大家更好的學習和理解。對本文有任何補充之處,歡迎大家指出。
首先來看看題目是如何要求的(百度迅雷校招筆試題)。
一、字串的排列
用C++寫一個函式, 如 Foo(const char *str), 打印出 str 的全排列,
如 abc 的全排列: abc, acb, bca, dac, cab, cba

一、全排列的遞迴實現

為方便起見,用123來示例下。123的全排列有123、132、213、231、312、321這六種。首先考慮213和321這二個數是如何得出的。顯然這二個都是123中的1與後面兩數交換得到的。然後可以將123的第二個數和每三個數交換得到132。同理可以根據213和321來得231和312。因此可以知道——全排列就是從第一個數字起每個數分別與它後面的數字交換。找到這個規律後,遞迴的程式碼就很容易寫出來了:

[cpp] view plain copy print?
  1. #include<iostream>
  2. usingnamespace std;  
  3. #include<assert.h>
  4. void Permutation(char* pStr, char* pBegin)  
  5. {  
  6.     assert(pStr && pBegin);  
  7.     if(*pBegin == '\0')  
  8.         printf("%s\n",pStr);  
  9.     else
  10.     {  
  11.         for(char* pCh = pBegin; *pCh != '\0'; pCh++)  
  12.         {  
  13.             swap(*pBegin,*pCh);  
  14.             Permutation(pStr, pBegin+1);  
  15.             swap(*pBegin,*pCh);  
  16.         }  
  17.     }  
  18. }  
  19. int main(void)  
  20. {  
  21.     char str[] = "abc";  
  22.     Permutation(str,str);  
  23.     return 0;  
  24. }  
#include<iostream>
using namespace std;
#include<assert.h>

void Permutation(char* pStr, char* pBegin)
{
	assert(pStr && pBegin);

	if(*pBegin == '\0')
		printf("%s\n",pStr);
	else
	{
		for(char* pCh = pBegin; *pCh != '\0'; pCh++)
		{
			swap(*pBegin,*pCh);
			Permutation(pStr, pBegin+1);
			swap(*pBegin,*pCh);
		}
	}
}

int main(void)
{
	char str[] = "abc";
	Permutation(str,str);
	return 0;
}

另外一種寫法:

[cpp] view plain copy print?
  1. //k表示當前選取到第幾個數,m表示共有多少個數
  2. void Permutation(char* pStr,int k,int m)  
  3. {  
  4.     assert(pStr);  
  5.     if(k == m)  
  6.     {  
  7.         staticint num = 1;  //區域性靜態變數,用來統計全排列的個數
  8.         printf("第%d個排列\t%s\n",num++,pStr);  
  9.     }  
  10.     else
  11.     {  
  12.         for(int i = k; i <= m; i++)  
  13.         {  
  14.             swap(*(pStr+k),*(pStr+i));  
  15.             Permutation(pStr, k + 1 , m);  
  16.             swap(*(pStr+k),*(pStr+i));  
  17.         }  
  18.     }  
  19. }  
  20. int main(void)  
  21. {  
  22.     char str[] = "abc";  
  23.     Permutation(str , 0 , strlen(str)-1);  
  24.     return 0;  
  25. }  
//k表示當前選取到第幾個數,m表示共有多少個數
void Permutation(char* pStr,int k,int m)
{
	assert(pStr);

	if(k == m)
	{
		static int num = 1;  //區域性靜態變數,用來統計全排列的個數
		printf("第%d個排列\t%s\n",num++,pStr);
	}
	else
	{
		for(int i = k; i <= m; i++)
		{
			swap(*(pStr+k),*(pStr+i));
			Permutation(pStr, k + 1 , m);
			swap(*(pStr+k),*(pStr+i));
		}
	}
}

int main(void)
{
	char str[] = "abc";
	Permutation(str , 0 , strlen(str)-1);
	return 0;
}
如果字串中有重複字元的話,上面的那個方法肯定不會符合要求的,因此現在要想辦法來去掉重複的數列。
二、去掉重複的全排列的遞迴實現
由於全排列就是從第一個數字起每個數分別與它後面的數字交換。我們先嚐試加個這樣的判斷——如果一個數與後面的數字相同那麼這二個數就不交換了。如122,第一個數與後面交換得212、221。然後122中第二數就不用與第三個數交換了,但對212,它第二個數與第三個數是不相同的,交換之後得到221。與由122中第一個數與第三個數交換所得的221重複了。所以這個方法不行。

換種思維,對122,第一個數1與第二個數2交換得到212,然後考慮第一個數1與第三個數2交換,此時由於第三個數等於第二個數,所以第一個數不再與第三個數交換。再考慮212,它的第二個數與第三個數交換可以得到解決221。此時全排列生成完畢。
這樣我們也得到了在全排列中去掉重複的規則——去重的全排列就是從第一個數字起每個數分別與它後面非重複出現的數字交換。下面給出完整程式碼:

[cpp] view plain copy print?
  1. #include<iostream>
  2. usingnamespace std;  
  3. #include<assert.h>
  4. //在[nBegin,nEnd)區間中是否有字元與下標為pEnd的字元相等
  5. bool IsSwap(char* pBegin , char* pEnd)  
  6. {  
  7.     char *p;  
  8.     for(p = pBegin ; p < pEnd ; p++)  
  9.     {  
  10.         if(*p == *pEnd)  
  11.             returnfalse;  
  12.     }  
  13.     returntrue;  
  14. }  
  15. void Permutation(char* pStr , char *pBegin)  
  16. {  
  17.     assert(pStr);  
  18.     if(*pBegin == '\0')  
  19.     {  
  20.         staticint num = 1;  //區域性靜態變數,用來統計全排列的個數
  21.         printf("第%d個排列\t%s\n",num++,pStr);  
  22.     }  
  23.     else
  24.     {  
  25.         for(char *pCh = pBegin; *pCh != '\0'; pCh++)   //第pBegin個數分別與它後面的數字交換就能得到新的排列   
  26.         {  
  27.             if(IsSwap(pBegin , pCh))  
  28.             {  
  29.                 swap(*pBegin , *pCh);  
  30.                 Permutation(pStr , pBegin + 1);  
  31.                 swap(*pBegin , *pCh);  
  32.             }  
  33.         }  
  34.     }  
  35. }  
  36. int main(void)  
  37. {  
  38.     char str[] = "baa";  
  39.     Permutation(str , str);  
  40.     return 0;  
  41. }  
#include<iostream>
using namespace std;
#include<assert.h>

//在[nBegin,nEnd)區間中是否有字元與下標為pEnd的字元相等
bool IsSwap(char* pBegin , char* pEnd)
{
	char *p;
	for(p = pBegin ; p < pEnd ; p++)
	{
		if(*p == *pEnd)
			return false;
	}
	return true;
}
void Permutation(char* pStr , char *pBegin)
{
	assert(pStr);

	if(*pBegin == '\0')
	{
		static int num = 1;  //區域性靜態變數,用來統計全排列的個數
		printf("第%d個排列\t%s\n",num++,pStr);
	}
	else
	{
		for(char *pCh = pBegin; *pCh != '\0'; pCh++)   //第pBegin個數分別與它後面的數字交換就能得到新的排列   
		{
			if(IsSwap(pBegin , pCh))
			{
				swap(*pBegin , *pCh);
				Permutation(pStr , pBegin + 1);
				swap(*pBegin , *pCh);
			}
		}
	}
}

int main(void)
{
	char str[] = "baa";
	Permutation(str , str);
	return 0;
}
OK,到現在我們已經能熟練寫出遞迴的方法了,並且考慮了字串中的重複資料可能引發的重複數列問題。那麼如何使用非遞迴的方法來得到全排列了?

三、全排列的非遞迴實現
要考慮全排列的非遞迴實現,先來考慮如何計算字串的下一個排列。如"1234"的下一個排列就是"1243"。只要對字串反覆求出下一個排列,全排列的也就迎刃而解了。
如何計算字串的下一個排列了?來考慮"926520"這個字串,我們從後向前找第一雙相鄰的遞增數字,"20"、"52"都是非遞增的,"26 "即滿足要求,稱前一個數字2為替換數,替換數的下標稱為替換點,再從後面找一個比替換數大的最小數(這個數必然存在),0、2都不行,5可以,將5和2交換得到"956220",然後再將替換點後的字串"6220"顛倒即得到"950226"。
對於像“4321”這種已經是最“大”的排列,採用STL中的處理方法,將字串整個顛倒得到最“小”的排列"1234"並返回false。

這樣,只要一個迴圈再加上計算字串下一個排列的函式就可以輕鬆的實現非遞迴的全排列演算法。按上面思路並參考STL中的實現原始碼,不難寫成一份質量較高的程式碼。值得注意的是在迴圈前要對字串排序下,可以自己寫快速排序的程式碼(請參閱《白話經典演算法之六 快速排序 快速搞定》),也可以直接使用VC庫中的快速排序函式(請參閱《使用VC庫函式中的快速排序函式》)。下面列出完整程式碼:

[cpp] view plain copy print?
  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstring>
  4. usingnamespace std;  
  5. #include<assert.h>
  6. //反轉區間
  7. void Reverse(char* pBegin , char* pEnd)  
  8. {  
  9.     while(pBegin < pEnd)  
  10.         swap(*pBegin++ , *pEnd--);  
  11. }  
  12. //下一個排列
  13. bool Next_permutation(char a[])  
  14. {  
  15.     assert(a);  
  16.     char *p , *q , *pFind;  
  17.     char *pEnd = a + strlen(a) - 1;  
  18.     if(a == pEnd)  
  19.         returnfalse;  
  20.     p = pEnd;  
  21.     while(p != a)  
  22.     {  
  23.         q = p;  
  24.         p--;  
  25.         if(*p < *q)  //找降序的相鄰2數,前一個數即替換數  
  26.         {  
  27.              //從後向前找比替換點大的第一個數
  28.             pFind = pEnd;  
  29.             while(*pFind < *p)  
  30.                 --pFind;  
  31.             swap(*p , *pFind);  
  32.             //替換點後的數全部反轉
  33.             Reverse(q , pEnd);  
  34.             returntrue;  
  35.         }  
  36.     }  
  37.     Reverse(a , pEnd);   //如果沒有下一個排列,全部反轉後返回false   
  38.     returnfalse;  
  39. }  
  40. int cmp(constvoid *a,constvoid *b)  
  41. {  
  42.     returnint(*(char *)a - *(char *)b);  
  43. }  
  44. int main(void)  
  45. {  
  46.     char str[] = "bac";  
  47.     int num = 1;  
  48.     qsort(str , strlen(str),sizeof(char),cmp);  
  49.     do
  50.     {  
  51.         printf("第%d個排列\t%s\n",num++,str);   
  52.     }while(Next_permutation(str));  
  53.     return 0;  
  54. }  
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#include<assert.h>

//反轉區間
void Reverse(char* pBegin , char* pEnd)
{
	while(pBegin < pEnd)
		swap(*pBegin++ , *pEnd--);
}
//下一個排列
bool Next_permutation(char a[])
{
	assert(a);
	char *p , *q , *pFind;
	char *pEnd = a + strlen(a) - 1;
	if(a == pEnd)
		return false;
	p = pEnd;
	while(p != a)
	{
		q = p;
		p--;
		if(*p < *q)  //找降序的相鄰2數,前一個數即替換數  
		{
			 //從後向前找比替換點大的第一個數
			pFind = pEnd;
			while(*pFind < *p)
				--pFind;
			swap(*p , *pFind);
			//替換點後的數全部反轉
			Reverse(q , pEnd);
			return true;
		}
	}
	Reverse(a , pEnd);   //如果沒有下一個排列,全部反轉後返回false   
	return false;
}

int cmp(const void *a,const void *b)
{
	return int(*(char *)a - *(char *)b);
}
int main(void)
{
	char str[] = "bac";
	int num = 1;
	qsort(str , strlen(str),sizeof(char),cmp);
	do
	{
		printf("第%d個排列\t%s\n",num++,str); 
	}while(Next_permutation(str));
	return 0;
}
至此我們已經運用了遞迴與非遞迴的方法解決了全排列問題,總結一下就是:
1、全排列就是從第一個數字起每個數分別與它後面的數字交換。
2、去重的全排列就是從第一個數字起每個數分別與它後面非重複出現的數字交換。
3、全排列的非遞迴就是由後向前找替換數和替換點,然後由後向前找第一個比替換數大的數與替換數交換,最後顛倒替換點後的所有資料。

二、字串的組合

題目:輸入一個字串,輸出該字串中字元的所有組合。舉個例子,如果輸入abc,它的組合有a、b、c、ab、ac、bc、abc。

上面我們詳細討論瞭如何用遞迴的思路求字串的排列。同樣,本題也可以用遞迴的思路來求字串的組合。

假設我們想在長度為n的字串中求m個字元的組合。我們先從頭掃描字串的第一個字元。針對第一個字元,我們有兩種選擇:第一是把這個字元放到組合中去,接下來我們需要在剩下的n-1個字元中選取m-1個字元;第二是不把這個字元放到組合中去,接下來我們需要在剩下的n-1個字元中選擇m個字元。這兩種選擇都很容易用遞迴實現。下面是這種思路的參考程式碼:
[cpp] view plain copy print?
  1. #include<iostream>
  2. #include<vector>
  3. #include<cstring>
  4. usingnamespace std;  
  5. #include<assert.h>
  6. void Combination(char *string ,int number,vector<char> &result);  
  7. void Combination(char *string)  
  8. {  
  9.     assert(string != NULL);  
  10.     vector<char> result;  
  11.     int i , length = strlen(string);  
  12.     for(i = 1 ; i <= length ; ++i)  
  13.         Combination(string , i ,result);  
  14. }  
  15. void Combination(char *string ,int number , vector<char> &result)  
  16. {  
  17.     assert(string != NULL);  
  18.     if(number == 0)  
  19.     {  
  20.         staticint num = 1;  
  21.         printf("第%d個組合\t",num++);  
  22.         vector<char>::iterator iter = result.begin();  
  23.         for( ; iter != result.end() ; ++iter)  
  24.             printf("%c",*iter);  
  25.         printf("\n");  
  26.         return ;  
  27.     }  
  28.     if(*string == '\0')  
  29.         return ;  
  30.     result.push_back(*string);  
  31.     Combination(string + 1 , number - 1 , result);  
  32.     result.pop_back();  
  33.     Combination(string + 1 , number , result);  
  34. }  
  35. int main(void)  
  36. {  
  37.     char str[] = "abc";  
  38.     Combination(str);  
  39.     return 0;  
  40. }  
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
#include<assert.h>

void Combination(char *string ,int number,vector<char> &result);

void Combination(char *string)
{
	assert(string != NULL);
	vector<char> result;
	int i , length = strlen(string);
	for(i = 1 ; i <= length ; ++i)
		Combination(string , i ,result);
}

void Combination(char *string ,int number , vector<char> &result)
{
	assert(string != NULL);
	if(number == 0)
	{
		static int num = 1;
		printf("第%d個組合\t",num++);

		vector<char>::iterator iter = result.begin();
		for( ; iter != result.end() ; ++iter)
			printf("%c",*iter);
		printf("\n");
		return ;
	}
	if(*string == '\0')
		return ;
	result.push_back(*string);
	Combination(string + 1 , number - 1 , result);
	result.pop_back();
	Combination(string + 1 , number , result);
}

int main(void)
{
	char str[] = "abc";
	Combination(str);
	return 0;
}

由於組合可以是1個字元的組合,2個字元的字元……一直到n個字元的組合,因此在函式void Combination(char* string),我們需要一個for迴圈。另外,我們用一個vector來存放選擇放進組合裡的字元。
方法二:用位運算來實現求組合

[cpp] view plain copy print?
  1. #include<iostream>
  2. usingnamespace std;  
  3. int a[] = {1,3,5,4,6};  
  4. char str[] = "abcde";  
  5. void print_subset(int n , int s)  
  6. {  
  7.     printf("{");  
  8.     for(int i = 0 ; i < n ; ++i)  
  9.     {  
  10.         if( s&(1<<i) )         // 判斷s的二進位制中哪些位為1,即代表取某一位
  11.             printf("%c ",str[i]);   //或者a[i]
  12.     }  
  13.     printf("}\n");  
  14. }  
  15. void subset(int n)  
  16. {  
  17.     for(int i= 0 ; i < (1<<n) ; ++i)  
  18.     {  
  19.         print_subset(n,i);  
  20.     }  
  21. }  
  22. int main(void)  
  23. {  
  24.     subset(5);  
  25.     return 0;  
  26. }  
#include<iostream>
using namespace std;

int a[] = {1,3,5,4,6};
char str[] = "abcde";

void print_subset(int n , int s)
{
	printf("{");
	for(int i = 0 ; i < n ; ++i)
	{
		if( s&(1<<i) )         // 判斷s的二進位制中哪些位為1,即代表取某一位
			printf("%c ",str[i]);   //或者a[i]
	}
	printf("}\n");
}

void subset(int n)
{
	for(int i= 0 ; i < (1<<n) ; ++i)
	{
		print_subset(n,i);
	}
}



int main(void)
{
	subset(5);
	return 0;
}

字串全排列擴充套件----八皇后問題
    題目:在8×8的國際象棋上擺放八個皇后,使其不能相互攻擊,即任意兩個皇后不得處在同一行、同一列或者同一對角斜線上。下圖中的每個黑色格子表示一個皇后,這就是一種符合條件的擺放方法。請求出總共有多少種擺法。


    這就是有名的八皇后問題。解決這個問題通常需要用遞迴,而遞迴對程式設計能力的要求比較高。因此有不少面試官青睞這個題目,用來考察應聘者的分析複雜問題的能力以及程式設計的能力。

由於八個皇后的任意兩個不能處在同一行,那麼這肯定是每一個皇后佔據一行。於是我們可以定義一個數組ColumnIndex[8],陣列中第i個數字表示位於第i行的皇后的列號。先把ColumnIndex的八個數字分別用0-7初始化,接下來我們要做的事情就是對陣列ColumnIndex做全排列。由於我們是用不同的數字初始化陣列中的數字,因此任意兩個皇后肯定不同列。我們只需要判斷得到的每一個排列對應的八個皇后是不是在同一對角斜線上,也就是陣列的兩個下標i和j,是不是i-j==ColumnIndex[i]-Column[j]或者j-i==ColumnIndex[i]-ColumnIndex[j]。

關於排列的詳細討論,詳見上面的講解。
接下來就是寫程式碼了。思路想清楚之後,編碼並不是很難的事情。下面是一段參考程式碼:

[cpp] view plain copy print?
  1. #include<iostream>
  2. usingnamespace std;  
  3. int g_number = 0;  
  4. void Permutation(int * , int  , int );  
  5. void Print(int * , int );  
  6. void EightQueen( )  
  7. {  
  8.     constint queens = 8;  
  9.     int ColumnIndex[queens];  
  10.     for(int i = 0 ; i < queens ; ++i)  
  11.         ColumnIndex[i] = i;    //初始化
  12.     Permutation(ColumnIndex , queens , 0);  
  13. }  
  14. bool Check(int ColumnIndex[] , int length)  
  15. {  
  16.     int i,j;  
  17.     for(i = 0 ; i < length; ++i)  
  18.     {  
  19.         for(j = i + 1 ; j < length; ++j)  
  20.         {  
  21.             if( i - j == ColumnIndex[i] - ColumnIndex[j] || j - i == ColumnIndex[i] - ColumnIndex[j])   //在正、副對角線上
  22.                 returnfalse;  
  23.         }  
  24.     }  
  25.     returntrue;  
  26. }  
  27. void Permutation(int ColumnIndex[] , int length , int index)  
  28. {  
  29.     if(index == length)  
  30.     {  
  31.         if( Check(ColumnIndex , length) )   //檢測棋盤當前的狀態是否合法
  32.         {  
  33.             ++g_number;  
  34.             Print(ColumnIndex , length);  
  35.         }  
  36.     }  
  37.     else
  38.     {  
  39.         for(int i = index ; i < length; ++i)   //全排列
  40.         {  
  41.             swap(ColumnIndex[index] , ColumnIndex[i]);  
  42.             Permutation(ColumnIndex , length , index + 1);  
  43.             swap(ColumnIndex[index] , ColumnIndex[i]);  
  44.         }  
  45.     }  
  46. }  
  47. void Print(int ColumnIndex[] , int length)  
  48. {  
  49.     printf("%d\n",g_number);  
  50.     for(int i = 0 ; i < length; ++i)  
  51.         printf("%d ",ColumnIndex[i]);  
  52.     printf("\n");  
  53. }  
  54. int main(void)  
  55. {  
  56.     EightQueen();  
  57.     return 0;  
  58. }  
#include<iostream>
using namespace std;

int g_number = 0;
void Permutation(int * , int  , int );
void Print(int * , int );

void EightQueen( )
{
	const int queens = 8;
	int ColumnIndex[queens];
	for(int i = 0 ; i < queens ; ++i)
		ColumnIndex[i] = i;    //初始化
	Permutation(ColumnIndex , queens , 0);
}

bool Check(int ColumnIndex[] , int length)
{
	int i,j;
	for(i = 0 ; i < length; ++i)
	{
		for(j = i + 1 ; j < length; ++j)
		{
			if( i - j == ColumnIndex[i] - ColumnIndex[j] || j - i == ColumnIndex[i] - ColumnIndex[j])   //在正、副對角線上
				return false;
		}
	}
	return true;
}
void Permutation(int ColumnIndex[] , int length , int index)
{
	if(index == length)
	{
		if( Check(ColumnIndex , length) )   //檢測棋盤當前的狀態是否合法
		{
			++g_number;
			Print(ColumnIndex , length);
		}
	}
	else
	{
		for(int i = index ; i < length; ++i)   //全排列
		{
			swap(ColumnIndex[index] , ColumnIndex[i]);
			Permutation(ColumnIndex , length , index + 1);
			swap(ColumnIndex[index] , ColumnIndex[i]);
		}
	}
}

void Print(int ColumnIndex[] , int length)
{
	printf("%d\n",g_number);
	for(int i = 0 ; i < length; ++i)
		printf("%d ",ColumnIndex[i]);
	printf("\n");
}

int main(void)
{
	EightQueen();
	return 0;
}
轉載:http://zhedahht.blog.163.co

題目:輸入兩個整數n和m,從數列1,2,3...n中隨意取幾個數,使其和等於m,要求列出所有的組合。

[cpp] view plain copy print?
  1. #include <iostream>
  2. #include <list>
  3. usingnamespace std;  
  4. list<int> list1;  
  5. void find_factor(int sum,int n)  
  6. {  
  7.     //遞迴出口
  8.     if(n<=0||sum<=0)  
  9.         return;  
  10.     //輸出找到的數
  11.     if(sum==n)  
  12.     {  
  13.         list1.reverse();  
  14.         for(list<int>::iterator iter=list1.begin();iter!=list1.end();iter++)  
  15.             cout<<*iter<<"+";  
  16.         cout<<n<<endl;  
  17.         list1.reverse();  
  18.     }  
  19.     list1.push_front(n);  
  20.     find_factor(sum-n,n-1);//n放在裡面
  21.     list1.pop_front();  
  22.     find_factor(sum,n-1);//n不放在裡面
  23. }  
  24. int main(void)  
  25. {  
  26.     int sum,n;  
  27.     cin>>sum>>n;  
  28.     cout<<"所有可能的序列,如下:"<<endl;  
  29.     find_factor(sum,n);  
  30.     return 0;  
  31. }  
#include <iostream>
#include <list>
using namespace std;
list<int> list1;
void find_factor(int sum,int n)
{
	//遞迴出口
	if(n<=0||sum<=0)
		return;
	//輸出找到的數
	if(sum==n)
	{
		list1.reverse();
		for(list<int>::iterator iter=list1.begin();iter!=list1.end();iter++)
			cout<<*iter<<"+";
		cout<<n<<endl;
		list1.reverse();
	}
	list1.push_front(n);
	find_factor(sum-n,n-1);//n放在裡面
	list1.pop_front();
	find_factor(sum,n-1);//n不放在裡面
}

int main(void)
{
	int sum,n;
	cin>>sum>>n;
	cout<<"所有可能的序列,如下:"<<endl;
	find_factor(sum,n);
	return 0;
}

相關推薦

演算法-字串排列問題

轉載地址:http://blog.csdn.net/hackbuteer1/article/details/7462447 全排列在筆試面試中很熱門,因為它難度適中,既可以考察遞迴實現,又能進一步考察非遞迴的實現,便於區分出考生的水平。所以在百度和迅雷的校園招聘以及程式設

[演算法學習]Java實現字串排列

思路:這裡用到遞迴的方式完成字元資料的全排列,遞迴確實很方便。看似沒用到輔助空間,實際上卻是消耗了棧空間(“遞迴棧”),遞迴用起來也不是那麼簡單,解決問題用遞迴的時候,一定要關注到兩個零界點,怎麼

面試演算法學習-4-字串排列

題目描述 輸入一個字串,打印出該字串中字元的所有排列。 例如輸入字串abc,則輸出由字元a、b、c 所能排列出來的所有字串 abc、acb、bac、bca、cab 和 cba。 分析與解法 解法一、遞迴實現 從集合中依次選出每一個元素,作為排列的第一個元素,然後對剩餘的元素

字串排列演算法java實現

字串的全排列 遞迴方法實現要實現字串全排列 我覺得像是一種分治法的感覺。比如AB只有兩種 :AB BA到了ABC時可以抽出A 只看BC的話就是兩種,然後BC全排列之後放在A後面。隨後取出B對AC全排列放在B後面以此類推,此演算法非常精美 但是位數多了全排列數量會呈指數式增長。

php每日小知識-字串排列演算法

//從php中文網學習 //字串全排列演算法 /*全排列就是從n個不同元素中任取m(m≤n)個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的一個排列,當m=n時所有的排列情況叫全排列。

C語言版 輸出字串排列

問題:輸入一字串(要求不存在重複字元),打印出該字串中字元中字元的所有排列。  例如:輸入”abc”,輸出結果為abc, acb, bac, bca, cab和cba。 遇到這個問題,筆者搜了一下,網上有很多答案,但似乎沒有我想要的簡單一點的純C語言編寫的,所以自己動手寫了

字串排列(效能分析Java版)

具體的思路我就不寫了,借用網上的一張圖來表示: 我的程式碼如下: import java.util.*; public class Solution { public ArrayList<String> Permutation(String str

8.4-字串排列

Write a method to compute all permutations of a string 其實就是全排列。 #include <iostream> #include <vector> #include <string>

字串排列組合的遞迴實現-Java版

排列組合演算法用途廣泛, 需要掌握, 為降低門檻, 本文主要關注演算法的邏輯和簡易性, 未重視演算法效率. 結合網路書本上的實現和自己的需求, 這裡列有四個目標: 1. 所有元素的全排列: ab的全排列是ab, ba(順序相關); 2. 所有元素的全組合:

演算法--字串排列

       今天做了一個演算法題目,當時沒做出來,參考了一下網上的答案,雖然說弄明白了怎麼回事,但是感覺下次遇到了可能還是會做不出來,所以先把解題思路記下來,以後時常回顧一下。 題目描述:    輸入一個字串,按字典序打印出該字串中

動態規劃DP演算法實現排列

/* * 全排列  * 無相同元素 * 1. 取第1個元素插入空字串, 1種情況  * 2. 取第2個元素插入長度為1的字串, 1*2 = 2種情況, 例如 'b'插入"a",可以在'a'前, 'a'後  * 3. 取第3個元素插入長度為2的字串, 2*3 = 6種情況, 例

java字串排列問題(經典)

*原題如下:用1、2、2、3、4、6這六個數字,用java寫一個main函式,打印出所有不同的排列, *如:612234、412346等,要求:”4”不能在第三位,”3”與”6”不能相連. * *1把問題歸結為圖結構的遍歷問題。實際上6個數字就是六個結點,

【前端筆試】JavaScript實現字串排列

我個人認為前端工程師筆試題中,演算法題一般不難,也就這個難度,甚至比這還要簡單。這是我在筆試過程中遇到的一個題~下面分享一下解題思路。 大體結構:定義一個方法,傳入str變數,返回一個數組,包含所有排列: function fun(str){ v

回溯演算法 和 貪心演算法排列

一:簡介 (1)回溯法 又稱試探法 回溯法的基本做法是深度優先搜尋,是一種組織得井井有條的、能避免不必要重複搜尋的窮舉式搜尋演算法;基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。 適用場景:當遇到某一類問題時,它的問題可以分解,但是又不能得出明確的動態

每天一個演算法排列演算法

全排列演算法:給出一個有n個元素的集合,求出這個集合所有可能的排列。 一、 遞迴的方法 void permutation(char *arr, int k , int m){ if(

劍指offer-字串排列(有重複值)

一、問題描述 輸入一個字串,按字典序打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。 結果請按字母順序輸出。  輸入描述: 輸入一個字串,長度不超過9(可能有字元重複),字元只包

劍指Offer.38 字串排列(包含重複)

題目給定字串“abca”輸出其全部排列。分析:package 劍指Offer; import java.util.ArrayList; import java.util.List; public c

【探索-中級演算法排列

前提:沒有重複數字的序列 解法一: List<List<Integer>> result = new ArrayList<>(); public List<

Java簡單演算法——資料排列

題目: 將1-5,5個數字進行全排列,並輸出共有多少種方案? import java.util.Arrays; /* 將1-5,5個數字進行全排列,並輸出共有多少種方案 */ pu

字串排列 Java遞迴實現

思路:      字串的全排列和數字的全排列類似,舉個例子:字串為“ABC”,按照我們所學數學上的邏輯,先取出A,放入首位,剩下BC有兩種全排列情況,即ABC,ACB,同理,將A分別與B,C交換,於是字串"ABC"的全排列總共有6種。如何將這種邏輯轉換為程式碼:首先,可以肯定