最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++中字符串全排列算法及next_permutation原理詳解

 更新時間:2023年02月01日 11:29:23   作者:謎一樣的男人1  
這篇文章主要為大家詳細介紹了C++中字符串全排列(遞歸法)和(迭代法)以及next_permutation底層原理,文中的示例代碼講解詳細,感興趣的可以了解一下

前言

next_permutation/prev_permutation是C++ STL中的一種實用算法;

功能是: 以迭代器的方式,將一個容器內(nèi)容改變?yōu)樗南乱粋€(或prev上一個)全排列組合;

next_permutation的使用

假設需要將字符串a(chǎn)bcd的全排列依次打印,我們可以用next_permutation函數(shù)方便操作:

使用方法:

1.一般先sort成升序;(prev_permutation倒著全排列使用規(guī)則相反)

2.然后再do while配合調(diào)用全排列,循環(huán)輸出,直到排列情況全部輸出 返回false;

運行結(jié)果:

實現(xiàn)全排列的兩種算法

當然僅僅只會用沒有什么困哪的,如果面試官突然問你STL中這個全排列算法咋實現(xiàn)的呢?

1. 遞歸法(全排列方便理解記憶的方法,作為備用方法)

如果上面全排列,突然腦袋斷片了,或者說考試中不讓用封裝好的庫函數(shù);

為了不至于連個全排列的思想都不會,可以用用相對好理解的遞歸法全排列:

算法思想:(遞歸問題:按規(guī)則處理一個過程,剩下的過程是相同的處理方式,那么就可以進行函數(shù)遞歸調(diào)用)

1.從集合中依次選出每一個元素,作為排列的第一個元素;

2.然后**對剩余的元素(第一個元素之后的)進行 同樣操作 **;

如此遞歸處理,從而得到所有元素的全排列。

eg:

以對字符串a(chǎn)bc進行全排列為例,我們可以這么做:以abc為例

  • 固定a,遞歸求后面bc的排列:求好: abc,acb后,b交換到第一位置,得到bac,如下固定b遞歸b后面的排列:
  • 固定b,求后面ac的排列:bac,bca,求好后,c交換到第一位置,得到cba,如下固定c遞歸c后面的排列:
  • 固定c,求后面ba的排列:cba,cab;結(jié)束 一共a,b,c分別當?shù)谝粋€元素進行了全排列,算法結(jié)束;

(注意:1. 每次交換下一個位置的時候,需要swap換回來,保證原始序列,再交換下一個位置的字母去第一個位置。2. 需要考慮有重復相同且挨著的數(shù)字情況,此時需要剪枝)

遞歸比較抽象,可以用簡單地例子abc在紙上模擬畫一下好理解;

實現(xiàn)代碼(無重復元素情況)

#include<iostream>
#include<vector>
using namespace std;

//dfs實現(xiàn)全排列(無重復元素情況)
void dfs(string &s, int l, int r)
{
	if (l == r) {//遞歸終止,當前s可以輸出了,已經(jīng)是某一輪的完整排列,不能再排列了
		cout<<s<<endl;
		return;
	}

	for (int i = l; i < r; i++) {
        
            swap(s[l],s[i]);
			dfs(s,l+1,r);//遞歸
			swap(s[l], s[i]);//進行下一輪的swap dfs,需要先swap換回來原來的位置!否則會出現(xiàn)重復排列!
		
	}
}


int main()
{
	string s = "abcd";
    //sort(s.begin(),s.end())//sort一下,再配合dfs算法,可以實現(xiàn)按照字典序處理
    int len = s.size();
	dfs(s,0,len);
	return 0;
}

運行結(jié)果:

有重復元素情況

這種情況需要對代碼做一個優(yōu)化,不然的話按照上面的算法,會出現(xiàn)重復數(shù)字的重復排列情況;

優(yōu)化很簡單:

如果某個數(shù)字在之前的排列被換到首位置進行排列過,那本次交換就不進行;(其次,當dfs首次交換i==l的時候,即便出現(xiàn)過也需要進行);

整合一下就是if(i==l || s[i]沒出現(xiàn)) -->進行交換)

代碼:

#include<iostream>
#include<algorithm>
#include<set>
using namespace std;

//dfs實現(xiàn)全排列(含重復元素情況)
void dfs(string &s, int l, int r)
{
	if (l == r) {
		cout<<s<<endl;
		return;
	}
	set<char>st;//檢測重復的set
	for (int i = l; i < r; i++) {
		if (i == l || st.find(s[i])==st.end()) {//防止后續(xù)進行重復排列
			st.insert(s[i]);//滿足  記錄這個字符 

			swap(s[l], s[i]);
			dfs(s, l + 1, r);
			swap(s[l], s[i]);
		}
	}
}


int main()
{
	string s = "aba";
	int len = s.size();
	dfs(s,0,len);
	return 0;
}

2. 迭代法(next_permutation底層原理)

比較抽象,難以理解,根據(jù)個人情況來理解;

一個全排列可看做一個字符串,字符串可有前綴、后綴。

規(guī)定: 生成給定全排列的下一個排列–> 所謂一個字符串的下一個排列,就是這個個字符串變化限制在盡可能短的后綴上,變化后的那個字符串; 這就要求這一個與下

一個有盡可能長的共同前綴;變化限制在盡可能短的后綴上

eg:

839647521是1—9的排列。1—9的排列最前面的是123456789,最后面的987654321;

從右向左掃描若都是增的,就到了987654321,也就沒有下一個了。否則找出第一次出現(xiàn)下降的位置。

如何得到346987521的下一個?

首先對原生字符串排序,這個迭代算法是基于字典序排序好的字符串全排列;(所以之后從尾部,向前循環(huán)迭代,每次變化盡可能短的后綴,以此類推)

1.從尾部往前找第一個P(i-1) < P(i)的位置;: 346987521 種 最終找到6是第一個變小的數(shù)字,記錄下6的位置i-1

2.從找到的 i 位置往后找到最后一個大于6的數(shù):346987521 中最終找到7的位置,記錄位置為m(m == r-1)

3.swap(r-1,i-1) : 3 4 7 9 8 6 5 2 1

4.倒序翻轉(zhuǎn)i位置后的所有數(shù)據(jù) : 3 4 7 1 2 5 6 8 9

5.進行do-while循環(huán),直到第一步之后,判斷出 i==0 break; 全部排列完畢

很抽象,但是思想就是 一個字符串的下一個全排列:有盡可能長的共同前綴;變化限制在盡可能短的后綴上

大概知道步驟: 那么用排好序的123456789試試上面的過程,你會發(fā)現(xiàn),每次變化盡可能短的后綴,有點像遞歸的感覺,一步一步逼近字符串0,index,此時完美結(jié)束; 或者用123這個例子體驗一下6個全排列是咋來的 amazing

上面的過程多悟幾遍就理解了; 大概知道思想面試的時候說說也行=-=

實現(xiàn)代碼(有無重復不影響)

#include<iostream>
#include<algorithm>
#include<set>
using namespace std;

//dfs實現(xiàn)全排列



int main()
{
	string s = "abcd";
	
	sort(s.begin(),s.end());//記得先排序
	
	int len = s.size();
	do
	{
		cout << s << endl;//打印某次排列

		int i = s.size() - 1;
		int j;
		while (i > 0 && s[i] <= s[i - 1]) i--;//1.從后向前 找 第一個 s[i-1]<s[i]

		if (i == 0) break;

		j = i;

		while (j<len && s[j]>s[i - 1]) j++;//2.從i向后 找 最后一個 s[m]>s[i-1] 用j找,所以最后m==j-1

		swap(s[i - 1], s[j - 1]);//3. swap (i-1,m(j-1))

		reverse(s.begin() + i, s.end());  //4. 翻轉(zhuǎn) i后面的子串

		

	} while (1); //do while為了讓第一個 abcd 也正常打印再全排列

	return 0;
}

這個算法理解起來對于我來說有點夸張,嗚嗚嗚;

以上就是C++中字符串全排列算法及next_permutation原理詳解的詳細內(nèi)容,更多關于C++字符串全排列 next_permutation的資料請關注腳本之家其它相關文章!

相關文章

  • CreateCompatibleDC()函數(shù)案例詳解

    CreateCompatibleDC()函數(shù)案例詳解

    這篇文章主要介紹了CreateCompatibleDC()函數(shù)案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • 深入sizeof的使用詳解

    深入sizeof的使用詳解

    本篇文章是對sizeof的使用進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • VC基于ADO技術訪問數(shù)據(jù)庫的方法

    VC基于ADO技術訪問數(shù)據(jù)庫的方法

    這篇文章主要介紹了VC基于ADO技術訪問數(shù)據(jù)庫的方法,較為詳細的分析了VC使用ADO操作數(shù)據(jù)庫的相關實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • 帶你搞懂C++ LeeCode 二叉樹的中序遍歷

    帶你搞懂C++ LeeCode 二叉樹的中序遍歷

    中序遍歷(LDR)是二叉樹遍歷的一種,也叫做中根遍歷、中序周游。在二叉樹中,中序遍歷首先遍歷左子樹,然后訪問根結(jié)點,最后遍歷右子樹
    2021-07-07
  • 提升編程能力的C語言技巧總結(jié)

    提升編程能力的C語言技巧總結(jié)

    這篇文章主要為大家總結(jié)了一些C語言技巧的相關資料,可以幫助大家大大提升編程能力。文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2022-12-12
  • C++數(shù)據(jù)結(jié)構之二叉搜索樹的實現(xiàn)詳解

    C++數(shù)據(jù)結(jié)構之二叉搜索樹的實現(xiàn)詳解

    二叉搜索樹作為一個經(jīng)典的數(shù)據(jù)結(jié)構,具有鏈表的快速插入與刪除的特點,同時查詢效率也很優(yōu)秀,所以應用十分廣泛。本文將詳細講講二叉搜索樹的C++實現(xiàn),需要的可以參考一下
    2022-08-08
  • OLEDB打開Excel文件的實現(xiàn)方法

    OLEDB打開Excel文件的實現(xiàn)方法

    下面小編就為大家?guī)硪黄狾LEDB打開Excel文件的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • C++實現(xiàn)LeetCode(101.判斷對稱樹)

    C++實現(xiàn)LeetCode(101.判斷對稱樹)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(101.判斷對稱樹),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 基于C語言實現(xiàn)掃雷小游戲

    基于C語言實現(xiàn)掃雷小游戲

    這篇文章主要為大家詳細介紹了基于C語言實現(xiàn)掃雷小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • 新手小心:c語言中強符號與弱符號的使用

    新手小心:c語言中強符號與弱符號的使用

    本篇文章適合新手。是對c語言中強符號與弱符號的使用進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05

最新評論

临泉县| 阿瓦提县| 鄄城县| 岳阳县| 板桥市| 化隆| 赤壁市| 江源县| 泰顺县| 南宁市| 娱乐| 闸北区| 四平市| 万山特区| 铜川市| 黄石市| 襄樊市| 漯河市| 会昌县| 五家渠市| 长沙县| 西藏| 海淀区| 无为县| 正安县| 满洲里市| 涪陵区| 新绛县| 和平县| 郴州市| 平昌县| 彭阳县| 永德县| 武威市| 象山县| 平潭县| 大埔县| 天津市| 韩城市| 凤庆县| 孝感市|