C/C++字符串全排列(整数字符)及生成去重整数集
在刷各厂秋招笔试面试题的时候发现众多企业的研发岗比较喜欢考察对字符串的检索、查询等操作。
我最近遇到这样比较经典的题目:输入一个只包含整数字符的字符串,例如:“123”、“1125”等,输出这个字符串的前排列,以及生成这些所有由这些整数字符组合出的非重复整数,例如输入“111” 那么它生成的整数就只有111。
解决一个集合全排列的问题,最常用的莫过于回溯算法了,回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。算法过程如下图:
用回溯法生成全排列的函数实现如下:
void perm( string str, int low)
{
if (low == str.length() - 1) //终止条件:当对一个元素进行全排时打印输出
cout << str << endl;
else
{
for (int i = low; i < str.length(); i++) //遍历全排列范围的每个元素
{
std::swap(str[i], str[low]);//使得第一个元素(下标为low)分别与遍历中的每个元素进行位置互换
perm(arr, str, low + 1);//在上一步的基础上,其他的元素进行全排列(核心代码需要理解)
std::swap(str[i], str[low]);//回溯过程:数组中的元素分别与下标为p的的元素交换过位置,现在要复位。
}
}
}
当然本题还需要生成所有到去重整数,我们可以使用strtol()函数将每一次的排序的字符串转化为整数,并且加入到vector容器中,然后//组合使用unique()和erase()函数删除重复元素(unique()函数把vector中重复元素放到容器最后,然后使用erase()函数删除末尾的重复元素)
整体实现代码如下:
#include<iostream>
#include<vector>
#include<cmath>
#include<string>
#include <algorithm>
using namespace std;
void perm(vector<long>*arr, string str, int low)
{
if (low == str.length() - 1) //终止条件:当对一个元素进行全排时打印输出
{
cout << str << endl;
arr->push_back(strtol(str.c_str(), NULL, 10));//把当前序列转化为整数并且加入容器
}
else
{
for (int i = low; i < str.length(); i++) //遍历全排列范围的每个元素
{
std::swap(str[i], str[low]);//使得第一个元素(下标为low)分别与遍历中的每个元素进行位置互换
perm(arr, str, low + 1);//在上一步的基础上,其他的元素进行全排列(核心代码需要理解)
std::swap(str[i], str[low]);//回溯过程:数组中的元素分别与下标为p的的元素交换过位置,现在要复位。
}
}
}
void main()
{
string str;
cout << "输入整数字符串:" << endl;
cin >> str;
vector<long>arr;
cout << "全序列:" << endl;
perm(&arr, str, 0);
sort(arr.begin(), arr.end());//使用sort()函数对容器内元素升序排序
arr.erase(unique(arr.begin(), arr.end()), arr.end());//组合使用unique()和erase()函数删除重复元素
cout << "组成的数字有:" << endl;
for (auto i : arr)
cout << i << " ";
}
执行结果为: