1. 程式人生 > >[收集]字串的全排列和組合

[收集]字串的全排列和組合

今天學習了一下何海濤部落格中的第28題,字串的排列問題,實際上指的是字串的全排列問題(排列和全排列還是有區別的吧)。思考並研究了這題之後就考慮了一下不同條件下其他類似的題的解法的編寫,兩部分來自於何海濤,其他來自於網路,此處做搬運和收集工作。分別從四個方面考慮:一、字串的全排列
(1)若不考慮字串中有重複字元(即假設字串中無重複字元)
(2)若考慮字串中有重複字元(即假設字串中有重複字元)

二、字串的組合
(1)若不考慮字串中有重複字元(即假設字串中無重複字元)
(2)若考慮字串中有重複字元(即假設字串中有重複字元)


一、字串的全排列
(1)若不考慮字串中有重複字元(即假設字串中無重複字元)
此時“abc”的全排列為:abc

acbbacbcacabcba。

      我們以三個字元abc為例來分析一下求字串排列的過程。首先我們固定第一個字元a,求後面兩個字元bc的排列。當兩個字元bc的排列求好之後,我們把第一個字元a和後面的b交換,得到bac,接著我們固定第一個字元b,求後面兩個字元ac的排列。現在是把c放到第一位置的時候了。記住前面我們已經把原先的第一個字元a和後面的b做了交換,為了保證這次c仍然是和原先處在第一位置的a交換,我們在拿c和第一個字元交換之前,先要把ba交換回來。在交換ba之後,再拿c和處在第一位置的a進行交換,得到cba。我們再次固定第一個字元c,求後面兩個字元ba的排列。既然我們已經知道怎麼求三個字元的排列,那麼固定第一個字元之後求後面兩個字元的排列,就是典型的遞迴思路了。


void Permutation(char* pSrc,  char* pBegin)
{
	if (!pSrc || !pBegin)
	{
		return;
	}

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

			Permutation(pSrc, pBegin+1);

			temp = *pBegin;
			*pBegin = *pCh;
			*pCh = temp;
		}
	}
}


int main()
{
	char pSrc[] = "abc";

	Permutation(pSrc, pSrc);

	return 0;
}

執行結果是:



(2)若考慮字串中有重複字元(即假設字串中有重複字元)
上述思路非常好,但是若存在重複字元,則就不正確了,比如對於上述程式,輸入“aabc”,則輸出:


      就會出現重複的結果。我本來思考著如果在與*pBegin交換時加一個條件語句判斷是否相等,若與*pBegin相等就不交換,若不相等才交換,用“aabc”測試時結果確實正確了。但是實際上是錯誤的,比如用“abbc”測試時就不正確了。
      我也是看到了一個網友的方法才發現我上述考慮的方法是錯誤的,他的方法是判斷當前*pCh的字元(即準備與*pBegin交換的字元)在前面的子字串中是否出現過了,若出現了,就不交換,若沒出現就交換。程式碼如下:

void Permutation(char* pSrc,  char* pBegin)
{
	if (!pSrc || !pBegin)
	{
		return;
	}

	if (*pBegin == '\0')
	{
		printf("%s\n", pSrc);
	}
	else
	{
		for (char* pCh=pBegin; *pCh!='\0'; ++pCh)
		{
			if(strchr(pBegin, *pCh) == pCh)
			{
				char temp = *pBegin;
				*pBegin = *pCh;
				*pCh = temp;

				Permutation(pSrc, pBegin+1);

				temp = *pBegin;
				*pBegin = *pCh;
				*pCh = temp;
			}
		}
	}
}


int main()
{
	char pSrc[] = "abbc";

	Permutation(pSrc, pSrc);

	return 0;
}

執行結果是:



二、字串的組合
(1)若不考慮字串中有重複字元(即假設字串中無重複字元)
輸入一個字串,輸出該字串中字元的所有組合。舉個例子,如果輸入"abc",它的組合有abcabacbcabc

      本題也可以用遞迴的思路來求字串的組合。
      假設我們想在長度為n的字串中求m個字元的組合。我們先從頭掃描字串的第一個字元。針對第一個字元,我們有兩種選擇:一是把這個字元放到組合中去,接下來我們需要在剩下的n-1個字元中選取m-1個字元;而是不把這個字元放到組合中去,接下來我們需要在剩下的n-1個字元中選擇m
個字元。這兩種選擇都很容易用遞迴實現。下面是這種思路的參考程式碼:

void Combination(char* str, int number, vector<char>& result)
{
	if (str==NULL)
	{
		return;
	}

	if (number==0)
	{
		for (vector<char>::iterator ite = result.begin(); ite!=result.end(); ++ite)
		{
			cout<<*ite;
		}
		cout<<endl;
		return;
	}

	if (*str == '\0')
	{
		return;	
	}
	
	else
	{
		Combination(str+1, number, result);

		result.push_back(*str);
		Combination(str+1, number-1, result);
		result.pop_back();
	}

}


int main()
{
	char pSrc[] = "abc";

	vector<char> result;
	for (int i=1; i<=strlen(pSrc); ++i)
	{
		Combination(pSrc, i, result);
	}
	
	return 0;
}

      執行結果是:

也可以去掉上述中的迴圈:
void Combination(char* str, int number, vector<char>& result)
{
	if(*str == '\0')
	{
		
		for(vector<char>::iterator ite = result.begin();
			ite != result.end(); 
			++ite)
		{
			cout<<*ite;
		}
		cout<<endl;

		return;
	}

	result.push_back(*str);
	Combination(str + 1, number - 1, result);
	result.pop_back();

	Combination(str + 1, number-1, result);
}

int main()
{
	char pSrc[] = "abc";

	vector<char> result;
	Combination(pSrc, strlen(pSrc), result);

	return 0;
}


        另外,看到一個網友的思路:
用一個數組,模擬2進位制加法器,某一個為1,則取對應的字元,若為0則不取,就能夠實現字元組合。這個思路也非常好~ 不過是在字元長度不超過32的情況下。


(2)若考慮字串中有重複字元(即假設字串中有重複字元)
       但是上述程式碼在字串中有重複字元時就出問題了,如輸入”abbc“,則輸出為:


就出現了重複的結果。
        我想可以先去掉字串中所有重複的字元,比如由“abbcc”轉換成“abc”,再用上述演算法來做。不知道其他的更高效的演算法,待續......


相關推薦

[收集]字串排列組合

今天學習了一下何海濤部落格中的第28題,字串的排列問題,實際上指的是字串的全排列問題(排列和全排列還是有區別的吧)。思考並研究了這題之後就考慮了一下不同條件下其他類似的題的解法的編寫,兩部分來自於何海濤,其他來自於網路,此處做搬運和收集工作。分別從四個方面考慮:一、字串的全

字串排列組合演算法(遞迴非遞迴)

全排列在筆試面試中很熱門,因為它難度適中,既可以考察遞迴實現,又能進一步考察非遞迴的實現,便於區分出考生的水平。所以在百度和迅雷的校園招聘以及程式設計師和軟體設計師的考試中都考到了,因此本文對全排列作下總結幫助大家更好的學習和理解。對本文有任何補充之處,歡迎大家指出。

排列組合演算法的C#語言實現

using System; namespace Util.Comp { public class CombinationPermutation { public static void Main() { //全排列使用方法

字串排列所有組合問題及打靶問題

轉自:https://blog.csdn.net/a1937935900/article/details/77103955 問題1 :輸入一個字串,打印出該字串中字元的所有排列。例如輸入字串abc,則輸出由字元a、b、c所能排列出來的所有字串abc、acb、bac、bca、cab和cba。

字串排列組合

全排列: 主要思想:將字串第一個字元依次與後面字元交換,然後進行遞迴交換 在存在重複字元時需要加一個判斷,判斷之前是否交換過此字元。 bool isSwap(string str, int begin, int end) { for (int i = be

排列組合實現

.html 有意義 per more tro 包含 方法 循環 -s 記得@老趙之前在微博上吐槽說,“有的人真是毫無長進,六年前某同事不會寫程序輸出全排列,昨天發郵件還是問我該怎麽寫,這時間浪費到我都看不下去了。” 那時候就很好奇全排列到底是什

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

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

字串排列組合的JAVA實現

字串的組合: 給一個字串,比如ABC, 把所有的組合,即:A, B, C, AB, AC, BC, ABC, 都找出來。 解題思路: 假設我們想在長度為n的字串中求m個字元的組合。我們先從頭掃描字串的第一個字元。針對第一個字元,我們有兩種選擇:一是把這個字元放到組合

字串排列組合

題目描述: 輸入一個字串,打印出該字串中字元的所有排列。 基本思路: 從字串中選出一個字元作為排列的第一個字元,然後對剩餘的字元進行全排列,如此遞迴,從而得到所有字元的全排列。以對

排列組合的求解

不能 結果 整體 條件 構造 討論 個數 女生 排除法 1)使用“分類計數原理”還是“分步計數原理”要根據我們完成某件事時采取的方式而定,可以分類來完成這件事時用“分類計數原理”,需要分步來完成這件事時

字符串的排列組合問題

函數表 out 跳過 lis ++ else += 過程 pow 1、字符串的全排列 題目:{a,b,c}要求輸出{abc,acb,bac,bca,cab,cba}。 字符串全排列可以把字符串看成兩個部分,第一個部分為它的一個字符,第二部分是後面的字符。 分兩步完成:首先求

排列康托展開

bre 一位 個數 字典序 ... 由於 就是 div () 一、康托展開:全排列到一個自然數的雙射 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! ai為整數,並且0<=ai<i(1<=

遞迴——以排列n皇后問題舉例

筆記來自【晴神寶典】 一、遞迴 遞迴 就在於反覆呼叫自身函式,但是每次都把問題範圍縮小,直到範圍可以縮小到可以直接得到邊界資料的結果,然後在返回路上求出對應的解。以上可看出,遞迴很適合用來實現分治思想。 遞迴兩個很重要的組成組成: 1、遞迴邊界(出口); 2、遞迴式

javascript 字串排列組合

不重複字串的組合 輸入 輸出 沒有重複值的字串 所有可能的組合值 abc a,b,c,ab,bc,abc 思路 遞迴的思

C語言版 輸出字串排列

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

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

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

python字串的分割組合

1、split分割 互動模式下,將網站按照’.'分割開,分成一個列表 >>> 'www.baidu.com'.split('.') ['www', 'baidu', 'com'] 互動模式下,將路徑分割開 這種會報錯,因為由於有’\’。 &

8.4-字串排列

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

C++ STL求全排列組合

C++11 STL內建了求全排列的模板函式next_permutation和prev_permutation,屬於<algorithm>標頭檔案和std名稱空間,使用非常方便。例如: vector<int> A{1,2,3,4,5};

總結: 排列    全部子集 (深搜…

                                                                       暴力列舉 (參照劉汝佳程式碼) 找出集合中的全部排列組合: #include <cstdio> #include <iostream>