字母排列
一行给出一个由英文小写字母组成的单词 s。
把 s 的每个字母恰好用一次能组成的所有不同单词,按字典序(从第一个字母开始比较,字母靠前的在前)每行一个全部输出。
如果 s 中有重复字母,同一个单词可能出现多次,只输出一次(aab 时为 aab、aba、baa)。
- 输入
- 1 ≤ s 的长度 ≤ 7
- 输出
- 所有不同的单词,按字典序,每行一个
aab
aab aba baa
cab
abc acb bac bca cab cba
一行给出一个由英文小写字母组成的单词 s。
把 s 的每个字母恰好用一次能组成的所有不同单词,按字典序(从第一个字母开始比较,字母靠前的在前)每行一个全部输出。
如果 s 中有重复字母,同一个单词可能出现多次,只输出一次(aab 时为 aab、aba、baa)。
aab
aab aba baa
cab
abc acb bac bca cab cba
运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。
$ 就绪
请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。
一个递归同时解决重复和顺序。
先数好每个字母剩几个,在每个位置从 a 开始依次选一个“剩下的字母”,再进入下一个位置(选完后把个数恢复)。
同一个字母在一个位置只选一次,所以不会再生成相同的单词;从小字母开始选,自然就是字典序。
常见陷阱有两个。
Python itertools.permutations 区分的是位置而不是字母,所以 aab 会输出两次 aab。
用交换位置(swap)的方法,即使去掉重复也不是字典序。
工具也因语言而异。
C++ std::next_permutation 从排好序的字母开始,会按字典序无重复地给出下一个排列(不用递归);其他语言没有这样的标准函数。
7 个字母最多有 5,040 行,所以 Java、C# 先收集到 StringBuilder 再一次写出。
Craykon 中函数 늘어놓기(prefix) 调用自己,到底时用 返回; 返回。
各行收集到字符串 out 中,用 控制台.接着输出(out) 一次写出。
import sys s = input().strip()letters = sorted(set(s)) # 쓸 수 있는 글자(작은 것부터)left = {c: s.count(c) for c in letters} # 글자마다 남은 개수out = [] def arrange(prefix): if len(prefix) == len(s): out.append(prefix) return # 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, 작은 글자부터 고르니 사전 순이 된다 for c in letters: if left[c] > 0: left[c] -= 1 arrange(prefix + c) left[c] += 1 arrange("")sys.stdout.write("\n".join(out) + "\n")const s = require("fs").readFileSync(0, "utf8").trim();const letters = [...new Set(s)].sort(); // 쓸 수 있는 글자(작은 것부터)const left = new Map(letters.map((c) => [c, [...s].filter((x) => x === c).length]));const out = []; function arrange(prefix) { if (prefix.length === s.length) { out.push(prefix); return; } // 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, 작은 글자부터 고르니 사전 순이 된다 for (const c of letters) { if (left.get(c) > 0) { left.set(c, left.get(c) - 1); arrange(prefix + c); left.set(c, left.get(c) + 1); } }} arrange("");console.log(out.join("\n"));import { readFileSync } from "node:fs";const s: string = readFileSync(0, "utf8").trim();const letters: string[] = [...new Set(s)].sort(); // 쓸 수 있는 글자(작은 것부터)const left = new Map<string, number>(letters.map((c) => [c, [...s].filter((x) => x === c).length]));const out: string[] = []; function arrange(prefix: string): void { if (prefix.length === s.length) { out.push(prefix); return; } // 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, 작은 글자부터 고르니 사전 순이 된다 for (const c of letters) { const k = left.get(c)!; if (k > 0) { left.set(c, k - 1); arrange(prefix + c); left.set(c, k); } }} arrange("");console.log(out.join("\n"));import java.util.Scanner; public class Main { static int[] left = new int[26]; // 글자마다 남은 개수 static char[] path; static StringBuilder out = new StringBuilder(); static void arrange(int depth) { if (depth == path.length) { out.append(path).append('\n'); return; } // 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, a부터 고르니 사전 순이 된다 for (int c = 0; c < 26; c++) { if (left[c] > 0) { left[c]--; path[depth] = (char) ('a' + c); arrange(depth + 1); left[c]++; } } } public static void main(String[] args) { String s = new Scanner(System.in).next(); for (char ch : s.toCharArray()) left[ch - 'a']++; path = new char[s.length()]; arrange(0); System.out.print(out); }}using System;using System.Text; class Program{ static int[] left = new int[26]; // 글자마다 남은 개수 static char[] path; static StringBuilder output = new StringBuilder(); static void Arrange(int depth) { if (depth == path.Length) { output.Append(path).Append('\n'); return; } // 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, a부터 고르니 사전 순이 된다 for (int c = 0; c < 26; c++) { if (left[c] > 0) { left[c]--; path[depth] = (char)('a' + c); Arrange(depth + 1); left[c]++; } } } static void Main() { string s = Console.ReadLine().Trim(); foreach (char ch in s) left[ch - 'a']++; path = new char[s.Length]; Arrange(0); Console.Write(output); }}#include <array>#include <iostream>#include <string> std::array<int, 26> left{}; // 글자마다 남은 개수std::string path, out; void arrange(std::size_t depth) { if (depth == path.size()) { out += path; out += '\n'; return; } // 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, a부터 고르니 사전 순이 된다 for (int c = 0; c < 26; c++) { if (left[c] > 0) { left[c]--; path[depth] = static_cast<char>('a' + c); arrange(depth + 1); left[c]++; } }} int main() { std::string s; std::cin >> s; for (char ch : s) left[ch - 'a']++; path.assign(s.size(), ' '); arrange(0); std::cout << out;}#include <stdio.h>#include <string.h> static int left[26]; // 글자마다 남은 개수static char path[8];static int n; static void arrange(int depth) { if (depth == n) { puts(path); return; } // 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, a부터 고르니 사전 순이 된다 for (int c = 0; c < 26; c++) { if (left[c] > 0) { left[c]--; path[depth] = 'a' + c; arrange(depth + 1); left[c]++; } }} int main(void) { char s[8]; scanf("%7s", s); n = strlen(s); for (int i = 0; i < n; i++) left[s[i] - 'a']++; path[n] = '\0'; arrange(0); return 0;}// 같은 글자는 이 자리에서 한 번만 고르니 겹친 줄이 생기지 않고, 작은 글자부터 고르니 사전 순이 된다늘어놓기(prefix){ 如果 (prefix.长度 == s.长度) { out += prefix + "\n"; 返回; } 循环 (i = 0; i < letters.数量; i++) { 如果 (left[i] > 0) { left[i] -= 1; 늘어놓기(prefix + letters[i]); left[i] += 1; } }} s = 控制台.读行().去空白();// 쓸 수 있는 글자(작은 것부터)와 글자마다 남은 개수letters = [];遍历 (c 在 s){ 如果 (!letters.包含(c)) { letters.添加(c); }}letters.排序();left = 新列表(letters.数量, 0);遍历 (c 在 s){ left[letters.查找位置(c)] += 1;}out = "";늘어놓기("");控制台.接着输出(out);