3023. 字符组合

Fifnmar

这道题,如果用 C++,那么可以这样写去重:

string str;
cin >> str;
sort(str.begin(), str.end());
str.erase(unique(str.begin(), str.end()), str.end());

详见 C++ Primer (5th Ed.) 中文版 P343 或英文版 P384 关于 unique 等函数用法的讲解。

然后是排序输出的问题。可以简单地想到一个朴素算法:枚举去重后的字符串 str 中的每一个字符,分别有两种情况:

  • 不加

我以 "abc" 来解释一下。对第一个字符 'a',有要和不要两种选择,那么可以组出:

{"a", ""};

然后,对第二个字符,有要和不要两种选择,那么可以组出:

{"ab", "b", "a", ""};
 ^^^^^^^^^  ^^^^^^^
   选 'b'   不选 'b'

第三个同理。

可以发现,每次「不选」的情况下得到的结果就是上一步的内容,那么可以写出这样的等价的代码:

vector<string> strs({""});
for (uint32_t i = 0; i < str.size(); ++i) {
    for (uint32_t j = 0, sz = strs.size(); j < sz; ++j) {
        strs.push_back(strs[j] + str[i]);
    }
}

思考:如果一开始没有在 strs 里加入一个空字符串会怎样?

由于要按字典序输出,所以再排序一下就好了。从下标 1 开始输出,因为打头的元素是我们放置的哨兵空字符。

完整代码:

int main() {
    using namespace std;
    uint32_t t; cin >> t;
    for (uint32_t query = 0; query < t; ++query) {
        printf("case #%u:\n", query);
        string str; cin >> str;
        sort(str.begin(), str.end());
        str.erase(unique(str.begin(), str.end()), str.end());
        vector<string> strs({""});
        for (uint32_t i = 0; i < str.size(); ++i) {
            for (uint32_t j = 0, sz = strs.size(); j < sz; ++j) {
                strs.push_back(strs[j] + str[i]);
            }
        }
        sort(strs.begin(), strs.end());
        for (uint32_t i = 1; i < strs.size(); ++i) {
            printf("%s\n", strs[i].data());
        }
    }
}

不过按我一开始的想法不是这么做的。

观察输出的要求,可以看出就是在对 (0..str.size()) 的每个字符,在前面的选择的基础上,依次做这三种选择:

  • 加入当前位置的字符,并在此停止(把这个字符串放入答案数组)。
  • 加入当前位置的字符,并继续添加。
  • 不加入当前位置的字符,并继续添加。

代码:

std::string str;
std::vector<std::string> strs;

void arrange(uint32_t step, std::string const &crnt_str) {
    if (step != (uint32_t)str.size()) {
        strs.push_back(crnt_str + str[step]);
        arrange(step + 1, crnt_str + str[step]);
        arrange(step + 1, crnt_str);
    }
}

int main() {
    using namespace std;
    uint32_t t; cin >> t;
    for (uint32_t query = 0; query < t; ++query) {
        printf("case #%u:\n", query);
        cin >> str;
        sort(str.begin(), str.end());
        str.erase(unique(str.begin(), str.end()), str.end());
        strs.clear();
        arrange(0, string(""));
        for (auto const &s : strs) {
            printf("%s\n", s.data());
        }
    }
}
徐摆渡

参考了学长的思路,顺带学习了一下二进制枚举

#include <bits/stdc++.h>
using namespace std;

int T, cnt;
char str[20];
struct data
{
    char ans[100];
}d[1<<17];

bool cmp(data x, data y)
{
    return strcmp(x.ans,y.ans)<0;
}
int main()
{
    cin>>T;
    char ch=getchar();
    while(T--){
        gets(str);
        int len=strlen(str);

        //排序去重
        sort(str,str+len);
        int len1=1;
        for(int i=0, j=0;j<len;++j)
            if(str[j]!=str[i]) {str[++i]=str[j];len1++;}
        str[len1]='\0';

        //二进制枚举
        int len2=(1<<len1);
        for(int i=1;i<len2;++i){//从1开始空集不考虑
            int l=0;
            for(int j=0;j<len1;++j)
                if(i & (1 << j)) d[i-1].ans[l++]=str[j];
            d[i-1].ans[l]='\0';
        }

        //每个组合按字典序排好后输出
        sort(d,d+len2-1,cmp);
        printf("case #%d:\n",cnt++);
        for(int i=0;i<len2-1;++i)
            printf("%s\n",d[i].ans);
        memset(str,0,sizeof(str));
        memset(d,0,sizeof(d));
    }
    return 0;
}
13627999316

nice

Li Dao

首先把字符去重排序,然后学会二进制枚举每个字符取不取,最后字典序排序

include

using namespace std;
int T;
vector V;
vector ans;
void solve()
{
string strs;
cin>>strs;
int ll=strs.length();
V.clear();
for(int i=0;i<ll;i++) V.push_back(strs[i]);
sort(V.begin(),V.end());
V.resize(unique(V.begin(),V.end())-V.begin());

ll=V.size();
ans.clear();
for(int i=1;i<=(1<>=1;
}
//cout<<now<<endl;
ans.push_back(now);
}
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;

}
int main()
{
scanf(“%d”,&T);
for(int step=0;step<T;step++)
{
printf(“case #%d:\n”,step);
solve();
}
return 0;
}

Andrew-Malcom
本质上是二进制枚举做法
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t,k=0;cin>>t;
    while(t--){
        cout<<"case #"<<k++<<":\n";
        set<char>S;
        vector<char>str;
        vector<string>out;
        string s;cin>>s;
        for(int i=0;i<s.size();i++) S.insert(s[i]);
        for(set<char>::iterator it=S.begin();it!=S.end();it++){
            str.push_back(*it);
        }
        for(int i=0;i<(1<<(str.size()));i++){
            string ss="";
            for(int j=0;j<str.size();j++){
                if(i&(1<<j)) ss+=str[j]; 
            }
            if(ss!="")
                out.push_back(ss);
        }
        sort(out.begin(),out.end());
        for(int i=0;i<out.size();i++) cout<<out[i]<<endl;
    }
}
Mrhuo

用了类似深度优先想法,用一个递归函数从当前step到最后一个字母循环递归,用vector来储存要输出的字符串。

include

include

include

using namespace std;
list arr;
void print(string a,int step);

int cmp(char a,char b)
{
if(a>T;
int cixu=0;
while(T–)
{
string b;
cin>>b;
string a;
for(int i=0;i<b.size();i++)
{
bool flag=1;
for(int j=0;j<a.size();j++)
{
if(b[i]==a[j])
{
flag=0;
break;
}
}
if(flag==1)
{
a.push_back(b[i]);
}
}
cout<<”case #”<<cixu++<<”:”<<endl;
sort(a.begin(),a.end(),cmp);
print(a,0);
}
}
void print(string a,int step)
{
if(step==a.size())
return ;
for(int i=step;i<a.size();i++)
{
if(i!=a.size())
{
arr.push_back(a[i]);
for(list::iterator it=arr.begin();it!=arr.end();it++)
{
cout<<*it;
}
cout<<endl;
print(a,i+1);
arr.pop_back();
}
}
}

10165101161

首先把字符去重排序,然后学会二进制枚举每个字符取不取,最后字典序排序
哈哈 我也第一反应是这个

你当前正在回复 博客/题目
存在问题!