The first line gives the number of words n, and the second line gives n lowercase English words separated by single spaces. Words that use the same letters the same number of times, differing only in the order, are called anagrams (eat, tea, ate). Group the words into anagrams. If the same word appears several times, put every occurrence into its group. For each group print one line "count: word word …". Write the words of a group in dictionary order (compare from the first letter, the earlier letter of the alphabet goes first, and if one word is the beginning of the other, the shorter goes first). Print groups with more words first. If two groups have the same number of words, compare their first words (the first word of each sorted group) in dictionary order and print the group whose first word comes earlier first.
Input
1 ≤ n ≤ 5000, each word is 1 to 10 lowercase English letters
Output
One line per group: the number of words, a colon (:), and then each word preceded by one space
Example 1 · stdin
6
eat tea tan ate nat bat
stdout
3: ate eat tea
2: nat tan
1: bat
Example 2 · stdin
7
listen silent enlist google banana elgoog tinsel
stdout
4: enlist listen silent tinsel
2: elgoog google
1: banana
main.py
Error List00F8 ↓ · ⇧F8 ↑
Input (stdin)
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
Anagrams have the same string of sorted letters (eat, tea → aet), so group by that as a map key. The trap is the type of the key. Python sorted(w) is a list and raises TypeError as a key, so build a string with "".join(sorted(w)). In JS, using the array [...w].sort() as a Map key fails because arrays are equal only when they are the same object, so every word ends up alone (add .join("")). In Java and C#, a char[] key is also compared as an array object, not by content, so turn it into new String(c) / new string(c). A C++ std::string is a value, so the sorted copy works as a key directly. In Craykon you put the letters in a list, Sort() (정렬()), and Join("") (잇기("")) to make the key. Using the sum of character codes as the key is another common mistake: ad and bc (97+100 = 98+99) land in one group. C has no map, so qsort by (sorted letters, word): each group comes out together and already in dictionary order. When iterating the groups, Python dict, JS Map and Craykon Keys (열쇠목록) give insertion order, Java HashMap and C# Dictionary promise no order, and C++ std::map gives key order. None of these is the output order, so sort again by "bigger group first, then first word". Sorting by size alone leaves equal-size groups in first-seen order.
Pythonmain.py · 13 lines
n = int(input())words = input().split()# 글자를 정렬한 문자열이 같으면 같은 묶음이다(eat, tea → "aet")groups = {}for w in words: key = "".join(sorted(w)) # sorted(w)는 목록이라 사전 열쇠가 될 수 없다 groups.setdefault(key, []).append(w)result = [sorted(g) for g in groups.values()]result.sort(key=lambda g: (-len(g), g[0])) # 큰 묶음 먼저, 같으면 첫 낱말 사전 순for g in result: print(f"{len(g)}: {' '.join(g)}")
JavaScriptmain.js · 14 lines
const [n, ...words] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/);// 글자를 정렬한 문자열이 같으면 같은 묶음이다(eat, tea → "aet")const groups = new Map();for (const w of words) { const key = [...w].sort().join(""); // 배열 그대로는 열쇠로 못 쓴다(배열은 같은 객체일 때만 같다) if (!groups.has(key)) groups.set(key, []); groups.get(key).push(w);}const result = [...groups.values()].map((g) => g.sort());const cmp = (a, b) => (a < b ? -1 : a > b ? 1 : 0);result.sort((a, b) => b.length - a.length || cmp(a[0], b[0])); // 큰 묶음 먼저, 같으면 첫 낱말console.log(result.map((g) => `${g.length}: ${g.join(" ")}`).join("\n"));
TypeScriptmain.ts · 16 lines
import { readFileSync } from "node:fs";const [, ...words]: string[] = readFileSync(0, "utf8").trim().split(/\s+/);// 글자를 정렬한 문자열이 같으면 같은 묶음이다(eat, tea → "aet")const groups = new Map<string, string[]>();for (const w of words) { const key = [...w].sort().join(""); // 배열 그대로는 열쇠로 못 쓴다(배열은 같은 객체일 때만 같다) const g = groups.get(key); if (g) g.push(w); else groups.set(key, [w]);}const result: string[][] = [...groups.values()].map((g) => g.sort());const cmp = (a: string, b: string): number => (a < b ? -1 : a > b ? 1 : 0);result.sort((a, b) => b.length - a.length || cmp(a[0], b[0])); // 큰 묶음 먼저, 같으면 첫 낱말console.log(result.map((g) => `${g.length}: ${g.join(" ")}`).join("\n"));
JavaMain.java · 30 lines
import java.io.*;import java.util.*;public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); br.readLine(); String[] words = br.readLine().trim().split(" "); // 글자를 정렬한 문자열이 같으면 같은 묶음이다(eat, tea → "aet") Map<String, List<String>> groups = new HashMap<>(); for (String w : words) { char[] c = w.toCharArray(); Arrays.sort(c); String key = new String(c); // char[] 그대로는 열쇠가 안 된다(배열은 내용이 아니라 객체로 비교) groups.computeIfAbsent(key, k -> new ArrayList<>()).add(w); } List<List<String>> result = new ArrayList<>(); for (List<String> g : groups.values()) { Collections.sort(g); result.add(g); } result.sort(Comparator.<List<String>>comparingInt(g -> -g.size()).thenComparing(g -> g.get(0))); StringBuilder out = new StringBuilder(); for (List<String> g : result) out.append(g.size()).append(": ").append(String.join(" ", g)).append('\n'); System.out.print(out); }}
C#Main.cs · 34 lines
using System;using System.Collections.Generic;using System.Linq;class Program{ static void Main() { Console.ReadLine(); string[] words = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); // 글자를 정렬한 문자열이 같으면 같은 묶음이다(eat, tea → "aet") var groups = new Dictionary<string, List<string>>(); foreach (string w in words) { char[] c = w.ToCharArray(); Array.Sort(c); string key = new string(c); // char[] 그대로는 열쇠가 안 된다(배열은 객체로 비교) if (!groups.TryGetValue(key, out var list)) { list = new List<string>(); groups[key] = list; } list.Add(w); } // 문자열은 Ordinal로 비교한다(기본 비교는 문화권 규칙을 따른다) var result = groups.Values .Select(g => g.OrderBy(w => w, StringComparer.Ordinal).ToList()) .OrderByDescending(g => g.Count) .ThenBy(g => g[0], StringComparer.Ordinal); foreach (var g in result) Console.WriteLine($"{g.Count}: {string.Join(" ", g)}"); }}
C++main.cpp · 35 lines
#include <algorithm>#include <iostream>#include <map>#include <string>#include <vector>int main() { int n; std::cin >> n; // 글자를 정렬한 문자열이 같으면 같은 묶음이다(eat, tea → "aet") std::map<std::string, std::vector<std::string>> groups; for (int i = 0; i < n; i++) { std::string w; std::cin >> w; std::string key = w; std::sort(key.begin(), key.end()); // std::string은 값이라 정렬한 복사본이 곧 열쇠 groups[key].push_back(w); // []가 없으면 빈 vector를 만들어 준다 } std::vector<std::vector<std::string>> result; for (auto& [key, g] : groups) { std::sort(g.begin(), g.end()); result.push_back(g); } std::sort(result.begin(), result.end(), [](const auto& a, const auto& b) { if (a.size() != b.size()) return a.size() > b.size(); // 큰 묶음 먼저 return a[0] < b[0]; // 같으면 첫 낱말 사전 순 }); for (const auto& g : result) { std::cout << g.size() << ":"; for (const auto& w : g) std::cout << " " << w; std::cout << "\n"; }}
Cmain.c · 55 lines
#include <stdio.h>#include <stdlib.h>#include <string.h>/* C에는 사전이 없다: (정렬한 글자, 낱말) 차례로 정렬하면 같은 묶음이 붙어 나오고 묶음 안도 사전 순이 된다 */typedef struct { char key[11]; char word[11];} Item;typedef struct { int start, size; /* items[start] ~ items[start + size - 1] */} Group;static Item items[5000];static Group groups[5000];static int cmp_char(const void *a, const void *b) { return *(const char *)a - *(const char *)b; }static int cmp_item(const void *a, const void *b) { const Item *x = a, *y = b; int c = strcmp(x->key, y->key); return c != 0 ? c : strcmp(x->word, y->word);}static int cmp_group(const void *a, const void *b) { const Group *x = a, *y = b; if (x->size != y->size) return y->size - x->size; /* 큰 묶음 먼저 */ return strcmp(items[x->start].word, items[y->start].word); /* 같으면 첫 낱말 */}int main(void) { int n; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%10s", items[i].word); strcpy(items[i].key, items[i].word); qsort(items[i].key, strlen(items[i].key), 1, cmp_char); } qsort(items, n, sizeof(Item), cmp_item); int g = 0; for (int i = 0; i < n; i++) { if (i == 0 || strcmp(items[i].key, items[i - 1].key) != 0) groups[g++] = (Group){i, 0}; groups[g - 1].size++; } qsort(groups, g, sizeof(Group), cmp_group); for (int i = 0; i < g; i++) { printf("%d:", groups[i].size); for (int j = 0; j < groups[i].size; j++) printf(" %s", items[groups[i].start + j].word); printf("\n"); } return 0;}
Craykonmain.cray · 52 lines
Console.ReadLine();words = Console.ReadLine().Trim().Split();// 글자를 정렬한 문자열이 같으면 같은 묶음이다(eat, tea → "aet")groups = Dict();foreach (w in words){ key = 글자정렬(w); if (!groups.Contains(key)) { groups[key] = []; } groups[key].Add(w);}keys = groups.Keys;foreach (key in keys){ groups[key].Sort();}keys.Sort(큰묶음먼저);foreach (key in keys){ g = groups[key]; Console.WriteLine(g.Count + ": " + g.Join(" "));}// 낱말의 글자를 하나씩 목록에 담아 정렬한 뒤 다시 잇는다글자정렬(w){ c = []; for (i = 0; i < w.Length; i++) { c.Add(w[i]); } c.Sort(); return c.Join("");}// 큰 묶음 먼저, 크기가 같으면 첫 낱말이 사전 순으로 앞선 묶음 먼저큰묶음먼저(앞, 뒤){ if (groups[앞].Count != groups[뒤].Count) { return groups[뒤].Count - groups[앞].Count; } if (groups[앞][0] < groups[뒤][0]) { return -1; } return 1;}