首页 > 试题广场 >

小红的字符串构造

[编程题]小红的字符串构造
  • 热度指数:3210 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小红拿到了一个字符串s,她准备构造一个和s长度相同的字符串t:满足以下条件:
1. t的字符集和s的相同(去重后的,也就是说不考虑数量)
2. t的每个位置的字符都和s不同。
例如若 s="aabbc",那么t可以构造为"cbaca"。
你能帮帮小红吗?

输入描述:
输入一个仅由小写字母组成的字符串s,长度不超过 200000。


输出描述:
如果无解,请输出 -1。
否则输出任意合法的字符串。
示例1

输入

aabbc

输出

cbaca

说明

"bcacb"等字符串也是合法的构造。
构造,建立哈希表,比如字符串一共有abc三种字符,将a映射到b,b映射到c,c映射到a

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

unordered_set<char> uset;
unordered_map<char, char> umap;


int main() {
    string str;
    cin >> str;

    for (char ch : str) 
        uset.insert(ch);

    if (uset.size() == 1) 
        cout << "-1\n";


    else {
        vector<char> lib;
        for (auto ch : uset) lib.push_back(ch);

        int n = lib.size();

        for (int i = 0; i < n; i ++) umap[lib[i]] = lib[(i + 1) % n];

        for (char ch : str) 
            cout << umap[ch];
        

        cout << endl;
    }

    return 0;

    
}
// 64 位输出请用 printf("%lld")


编辑于 2024-11-12 13:30:42 回复(0)

Python版本

先把所有字符填一遍保证字符集一样,然后所有填过了,就可以随便只用两个字符填后面的了
c = list(input())

cnt = list(set(c))

vis = [0] * len(cnt)

if len(cnt) < 2:
    print(-1)
else:
    t = []
    for x in c:
        ok = False
        for i in range(len(vis)):
            if vis[i] == 0 and cnt[i] != x:
                t.append(cnt[i])
                vis[i] = 1
                ok = True
                break
        if sum(vis) == len(vis) and not ok:
            if cnt[0] != x:
                t.append(cnt[0])
            else:
                t.append(cnt[1])

    print("".join(t))


编辑于 2024-11-20 12:20:21 回复(1)
# 将输入字符串转换为字符列表
s = list(input())

# 初始化用于存储转换后字符的列表
t = []

# 初始化用于跟踪输入字符串中唯一字符的列表
char_set = []

# 初始化用于存储字符到字符映射的字典
char_map = {}

# 遍历输入字符串中的每个字符
for i in s:
    # 如果字符不在char_set中,则将其添加进去
    if i not in char_set:
        char_set.append(i)

# 检查char_set中的字符数量
# 如果少于2个字符,则无法进行有效的映射,输出-1
if len(char_set) < 2:
    print(-1)
else:
    # 创建字符到字符的映射
    for i in range(len(char_set)):
        # 如果是最后一个字符,则将其映射回第一个字符,形成循环
        if i == (len(char_set) - 1):
            char_map[char_set[i]] = char_set[0]
        else:
            # 否则,将字符映射到下一个字符
            char_map[char_set[i]] = char_set[i + 1]

    # 应用映射到输入字符串中的每个字符
    for i in s:
        # 使用char_map将字符转换为其映射字符,并添加到结果列表t中
        t.append(char_map[i])

    # 将结果列表t中的字符连接成一个字符串并打印
    print("".join(t))

发表于 2025-01-21 09:50:55 回复(0)
题目说不考虑数量,但是我没看见(
于是写成了要求字符种类和数量都要一致的构造qwq
不过居然神奇的过了(小声,可能是数据水了吧)
做法为贪心,统计每个字符出现的次数,放到优先队列里,每次取出频率最高的前两个进行兑换,最后将剩下的进行轮换,具体见代码
我觉得是对的,但没办法证明这种贪心不会漏掉所有有解的情况
大家有什么想法么??
#include <bits/stdc++.h>
using namespace std;
struct node
{
    char ch;
    int cnt;
};
bool operator <(node x,node y)
{
    return x.cnt<y.cnt;
}
priority_queue <node> q;
queue <char> q2[500];
int a[500];
int main() {
    string s;
    cin>>s;
    for(int i=0;i<s.size();i++)
        a[s[i]]++;
    for(int i=0;i<400;i++)
        if(a[i])
			q.push((node){char(i),a[i]});
    while(q.size()>=2)
    {
        node x,y;
        x=q.top();
		if(x.cnt==1) break;
        q.pop();
        y=q.top();
        q.pop();
        x.cnt--,y.cnt--;
        q2[y.ch].push(x.ch);
        q2[x.ch].push(y.ch);
        if(x.cnt) q.push(x);
		if(y.cnt) q.push(y);
    }
    if(q.size()<=1)
    {
    	cout<<"-1";
    	return 0;
	}
	char st=q.top().ch,lst=st;
	q.pop(); 
    while(!q.empty())
    {
    	node t=q.top();
    	q2[t.ch].push(lst);
    	q.pop();
    	lst=t.ch;
	}
	q2[st].push(lst);
	for(int i=0;i<s.size();i++)
	{
		char ch=q2[s[i]].front();
		q2[s[i]].pop();
		s[i]=ch;
	}
	cout<<s;
}
附上加强版(即考虑数量)的样例
aabccd
cbcada

aaabb
-1


发表于 2024-11-20 21:26:23 回复(0)
#include <iostream>
#include <iterator>
#include <queue>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
struct node{
    node(char c, int count): c(c), count(count){}
    char c;
    int count{0};
};
int main() {
    std::string s;
    std::cin >> s;
    std::unordered_set<char> set;
    for(auto c : s)
    {
        set.emplace(c);
    }
    if(set.size() == 1)
    {
        std::cout << -1;
        return 0;
    }
    auto Compare = [](const node& a, const node& b){
        return a.count >= b.count;
    };
    std::priority_queue<node, std::vector<node>, decltype(Compare)> list(Compare);
    for(auto c : set)
    {
        node nod(c, 0);
        list.emplace(nod);
    }
    std::vector<node> vec;
    for(int i = 0; i < s.size();)
    {
        node now = list.top();
        list.pop();
        if(now.c != s[i])
        {
            s[i] = now.c;
            now.count++;
            list.push(now);
            i++;
            while(vec.size() > 0)
            {
                list.push(vec.back());
                vec.pop_back();
            }
        }
        else {
            vec.push_back(now);
        }
    }
    std::cout << s;
}

一个比较好理解的思路是,先取出原本字符串的子集,然后将他们放到一个小顶堆中。堆中每个节点存储字符和已经使用的次数。每次取出堆顶的元素。如果能直接使用,就让它的计数加一然后再插回堆中,如果不能用,则拿出下一个元素来。然后再把之前取出的元素插回堆中。
实际上可以看出,只要原字符串中存在两个以上的不同元素,就一定能够生成一个新的字符串出来,所以后面不需要任何新的判定条件。
发表于 2025-04-22 16:52:48 回复(0)

蛋疼,java 2001ms,c++ 7ms

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

string s;

int main() {
    cin >> s;
    vector<int> chars(26, 0);
    for (char &c: s) {
        chars[c - 'a']++;
    }
    int base = -1, base2;
    int i = 0;
    while (i < 26) {
        if (chars[i] > 0) {
            base = i;
            ++i;
            break;
        }
        ++i;
    }
    base2 = base;
    while (i < 26) {
        if (chars[i] > 0) {
            chars[base] = i;
            base = i;
        }              
        ++i;  
    }
    if (base == base2) {
        cout << -1 << endl;
        return 0;
    } else {
        chars[base] = base2;
    }

    string res = "";

    for (char &c: s) {
        res += (char)('a' + chars[c - 'a']);
    }
    cout << res << endl;
    return 0;
}
发表于 2025-03-27 14:18:11 回复(0)
import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        HashSet<Character>set = new HashSet<>();
        int len = s.length();
        HashMap<Character,Boolean>map = new HashMap<>();
        for(int i = 0;i < len;i++)
        {
            char c = s.charAt(i);
            set.add(c);
            if(!map.isEmpty() && map.containsKey(c))
            {
                continue;
            }
            else
            {
                map.put(c,true);
            }
        }
        StringBuilder ans = new StringBuilder(len);
        for(int i = 0;i < len;i++)
        {
            char cur = s.charAt(i);
            int judge = 0;
            for(Character c : set)
            {
                if(!c.equals(cur))
                {
                    boolean f = map.get(c);
                    if(f)
                    {
                        ans.append(c);
                        judge = 1;
                        map.replace(c,false);
                        break;
                    }
                }
            }
            if(judge == 0)
            {
                for(Character c : set)
                {
                    if(!c.equals(cur))
                    {
                        ans.append(c);
                        break;
                    }
                }
            }
        }
        if(ans.length() < 1)
        {
            System.out.print(-1);
        }
        else
        {
            System.out.print(ans.toString());
        }
    }
}

发表于 2025-03-25 11:50:57 回复(0)
#include <iostream>
#include<cstring>
#include<unordered_set>
#include <vector>

using namespace std;

int main() {
    string s;
    cin >> s;
    int n = s.size();
    unordered_set<char> st;
    for (char ch : s) {
        st.insert(ch);
    }
    string t;
    vector<char> vec(st.begin(), st.end());
    int sz = vec.size();
    if (sz == 1) {
        cout << -1 << endl;
        return 0;
    }
    int idx = 0;
    for (int i = 0; i < n; i++) {
        if (vec[(idx) % sz] == s[i])
            idx++;
        t += vec[(idx++) % sz];
    }
    cout << t << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

发表于 2025-01-24 23:30:45 回复(0)
step1,将所有字符遍历一遍,获得所有不重复的字符构成的集合,这里使用STL中的set。
step2,将set中每一个元素映射到其上一个元素,得到一个hash表。
step3,重新遍历字符串,将每一个字符变成其在hash表中映射的值。

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

int main() {
    string str;
    cin >> str;
    set<char> st;
    for (char& c : str) {
        if (st.find(c) == st.end()) {
            st.insert(c);
        }
    }
    if (st.size() < 2) {
        cout << -1;
        return 0;
    }
    unordered_map<char, char> mp;
    char c = *st.begin();
    mp[c] = *st.rbegin();
    for (auto it = ++st.begin(); it != st.end(); ++it) {
        mp[*it] = c;
        c = *it;
    }
    for (char& c : str) {
        c = mp[c];
    }
    cout << str;
}

发表于 2024-12-16 14:32:59 回复(0)
把所有的字符以及位置保存一下,然后采用的策略是一号字符填充到二号字符的位置,二号字符填充到三号字符的位置,最后一个字符填充到一号字符的位置
那么无法出现满足要求的答案的情况就是只有一种字符的时候
注意只要求用的字符一样,没说出现频率也要求一样
#include <bits/stdc++.h>
 
using namespace std;
 
int main()
{
    string s;
    cin >> s;
    int n = s.length();
    string answer (n, ' ');
    unordered_map<char, vector<int>> occu;
    for (int i = 0; i < n; i++)
        occu[s[i]].push_back(i);
    if (occu.size() == 1)
        cout << "-1";
    else
    {
        vector<char> v;
        for (auto p : occu)
            v.push_back(p.first);
        for (int i = 0; i < v.size(); i++)
        {
            int j = (i + 1) % (v.size());
            for (auto x : occu[v[j]])
                answer[x] = v[i];
        }
        cout << answer;
    }
}


发表于 2024-07-18 14:41:08 回复(0)