一个字符串的全部子序列和全排列

1.打印一个字符串的全部子序列

way:选or不选,void go(string&s, int index, string path)中的path不能是引用,不然就会被影响,不使用引用就是为了他不影响我,我不影响他,形参果然是另外一个和我长得一样的人,但不是我。

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

//现在来的位置是s的index位置,之前做过的选择拼成的字符序列在path上
void go(vector<string>&result, string& s, int index, string path)
{
	if(index == s.size())
	{
		result.push_back(path);
		return;
	}
	//不选index位置处的字符
	go(result, s, index+1, path);
	path = path + s[index];
	//选index位置处的字符
	go(result, s, index+1, path);
}

void print(vector<string> vec)
{
	for(auto s:vec)
	{
		cout<<s<<endl;
	}
}

vector<string> getSubs(string s)
{
	string path="";
	vector<string> result;
	go(result,s,0,path);
	return result;
}

int main()
{
	string s="abcd";
	print(getSubs(s));

	system("pause");
	return 0;
}

如果非要写引用的话也可以这样写消除他对我的影响。

//现在来的位置是s的index位置,之前做过的选择拼成的字符序列在path上
void go(vector<string>&result, string& s, int index, string& path)
{
	string tmp=path;
	if(index == s.size())
	{
		result.push_back(path);
		return;
	}
	//不选index位置处的字符
	go(result, s, index+1, path);
	path = path + s[index];
	//选index位置处的字符
	go(result, s, index+1, path);
	path=tmp;
}

2.打印一个字符串的全部子序列,要求不要出现重复字面值的子序列。

way:用set去重。

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

//现在来的位置是s的index位置,之前做过的选择拼成的字符序列在path上
void go(set<string>&result, string& s, int index, string path)
{
	if(index == s.size())
	{
		result.insert(path);
		return;
	}
	//不选index位置处的字符
	go(result, s, index+1, path);
	path = path + s[index];
	//选index位置处的字符
	go(result, s, index+1, path);
}

void print(set<string> vec)
{
	for(auto s:vec)
	{
		cout<<s<<endl;
	}
}

set<string> getSubs(string s)
{
	string path="";
	set<string> result;
	go(result,s,0,path);
	return result;
}

int main()
{
	string s="abccd";
	print(getSubs(s));

	system("pause");
	return 0;
}

3.打印一个字符串的全部排列。

way:排列就不是选不选的问题了,而是先选谁后选谁的问题了,因为必须全都要选。

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

void go(vector<string>&result, string& s, string &path, map<int,bool>&vis)
{
	string tmp = path;
	if(path.size() == s.size())
	{
		result.push_back(path);
		return;
	}
	for(int i=0; i<s.size(); i++)
	{
		if(!vis[i])
		{
			vis[i]=true;
			path += s[i];
			go(result, s, path, vis);
			path =tmp;
			vis[i]=false;
		}
	}
}

vector<string> permutation(string s)
{
	string path="";
	vector<string> result;
	map<int,bool>vis;
	go(result,s,path,vis);
	return result;
}

void print(vector<string> vec)
{
	for(auto s:vec)
	{
		cout<<s<<endl;
	}
	cout<<vec.size()<<endl;
}

int main()
{
	string s="abcd";
	print(permutation(s));

	system("pause");
	return 0;
}

way2:用了rest表示剩余字符集合的方法,其实和上面的方法是一样的(上面是字符串s不变,用vis记录访问过的字符),这里是用了rest剩余的想法。

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

//rest为剩余的没选过的字符序列,path中放的是选过的字符序列,result是结果集
void go(vector<string>&result, string& rest, string path)
{
	if(rest.empty())
	{
		result.push_back(path);
		return;
	}
	//从rest中开始选字符
	for(int i=0; i<rest.size(); i++)
	{
		char ch = rest[i];
		//rest中移除当前字符,path加上当前字符
		rest.erase(rest.begin()+i);
		go(result, rest, path + ch);
		//恢复rest中的字符, 尝试选择下一个字符(一定要恢复在i位置,因为for是rest的循环,不然就在循环的过程中改变rest了)
		rest.insert(rest.begin()+i, ch);
	}
}

vector<string> permutation2(string s)
{
	vector<string> result;
	string path="";
	go(result, s, path);
	return result;
}

void print(vector<string>vec)
{
	for(auto num: vec)
	{
		cout<<num<<endl;
	}
	cout<<vec.size()<<endl;
}


int main()
{
	print(permutation2("abcde"));
	system("pause");
	return 0;
}

way3:把后面的字符往前换,另一种角度,return的条件需要注意下。

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

void swap(char& a, char& b)
{
	char tmp =a;
	a=b;
	b=tmp;
}

void go(vector<string>&result, string &s, int index)
{
	if(index == s.size())
	{
		result.push_back(s);
		return;
	}
	for(int i=index; i<s.size(); i++)
	{
		swap(s[index], s[i]);
		go(result, s, index+1);
		swap(s[i], s[index]);
	}
	
}

vector<string> permutation3(string s)
{
	vector<string> result;
	go(result, s, 0);
	return result;
}

void print(vector<string>vec)
{
	for(auto num: vec)
	{
		cout<<num<<endl;
	}
	cout<<vec.size()<<endl;
}


int main()
{
	print(permutation3("abcde"));
	system("pause");
	return 0;
}

way3的去重版,abccd这样子的去重,在当前选择的时候不能选重复的字符,vis的作用。

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

void swap(char& a, char& b)
{
	char tmp =a;
	a=b;
	b=tmp;
}

void go(vector<string>&result, string &s, int index)
{
	if(index == s.size())
	{
		result.push_back(s);
		return;
	}

	map<char,bool>vis;  //去重
	for(int i=index; i<s.size(); i++)
	{
		if(!vis[s[i]])
		{
			vis[s[i]]=true;
			swap(s[index], s[i]);
			go(result, s, index+1);
			swap(s[i], s[index]);
		}	
	}
	
}

vector<string> permutation3(string s)
{
	vector<string> result;
	go(result, s, 0);
	return result;
}

void print(vector<string>vec)
{
	for(auto num: vec)
	{
		cout<<num<<endl;
	}
	cout<<vec.size()<<endl;
}


int main()
{
	print(permutation3("abccd"));
	system("pause");
	return 0;
}

way2的去重版,一样的道理,在当前选择的时候不能选重复的字符,vis的作用。

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

//rest为剩余的没选过的字符序列,path中放的是选过的字符序列,result是结果集
void go(vector<string>&result, string& rest, string path)
{
	if(rest.empty())
	{
		result.push_back(path);
		return;
	}
	//去重
	map<char,bool>vis;
	//从rest中开始选字符
	for(int i=0; i<rest.size(); i++)
	{
		char ch = rest[i];
		if(!vis[ch])
		{
			vis[ch]=true;
			//rest中移除当前字符,path加上当前字符
			rest.erase(rest.begin()+i);
			go(result, rest, path + ch);
			//恢复rest中的字符, 尝试选择下一个字符(一定要恢复在i位置,因为for是rest的循环,不然就在循环的过程中改变rest了)
			rest.insert(rest.begin()+i, ch);
		}
	}
}

vector<string> permutation2(string s)
{
	vector<string> result;
	string path="";
	go(result, s, path);
	return result;
}

void print(vector<string>vec)
{
	for(auto num: vec)
	{
		cout<<num<<endl;
	}
	cout<<vec.size()<<endl;
}


int main()
{
	print(permutation2("abccd"));
	system("pause");
	return 0;
}

way的去重版,一样的道理,在当前选择的时候不能选重复的字符,chVis的作用。

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

void go(vector<string>&result, string& s, string &path, map<int,bool>&vis)
{
	string tmp = path;
	if(path.size() == s.size())
	{
		result.push_back(path);
		return;
	}
	map<char,bool>chVis;
	for(int i=0; i<s.size(); i++)
	{
		if(!vis[i] && !chVis[s[i]])
		{
			chVis[s[i]]=true;
			vis[i]=true;
			path += s[i];
			go(result, s, path, vis);
			path =tmp;
			vis[i]=false;
		}
	}
}

vector<string> permutation(string s)
{
	string path="";
	vector<string> result;
	map<int,bool>vis;
	go(result,s,path,vis);
	return result;
}

void print(vector<string> vec)
{
	for(auto s:vec)
	{
		cout<<s<<endl;
	}
	cout<<vec.size()<<endl;
}

int main()
{
	string s="abccd";
	print(permutation(s));

	system("pause");
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值