-
Notifications
You must be signed in to change notification settings - Fork 0
Create GroupAnagrams.md #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| # step1 何も見ずに解く | ||
| - ナイーブな実装だととても時間がかかりそう。効率的に処理する方法を考える | ||
| - HashMap<アルファベット順にソートしたstr, List<元のstr>>を作っていくのがいいか | ||
| - それぞれの単語の構成文字の出現個数をカウントする方法も思い浮かんだが、それをうまくHashMapのキーに変換する方法がパッと出てこなかった | ||
| - 1度Mapにつめて、ソートしながら連結するみたいなことを考えていた | ||
| - これであれば最初からソートしたほうがシンプルではやい | ||
| - step2で見てたら、入力がアルファベットのみであることを利用すればよかった | ||
| ## 解答 | ||
| ```java | ||
| class Solution { | ||
| public List<List<String>> groupAnagrams(String[] strs) { | ||
| HashMap<String, List<String>> sortedToAnagrams = new HashMap(); | ||
| for (String str : strs) { | ||
| String sortedStr = sortString(str); | ||
| sortedToAnagrams | ||
| // 新規登録の場合は初期値として空の配列をセット | ||
| .computeIfAbsent(sortedStr, (key) -> new ArrayList<>()) | ||
| .add(str); | ||
| } | ||
| return new ArrayList<>(sortedToAnagrams.values()); | ||
| } | ||
|
|
||
| private String sortString(String unsorted) { | ||
| char[] chars = unsorted.toCharArray(); | ||
| Arrays.sort(chars); | ||
| return new String(chars); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| # step2 他の方の解答を見る | ||
| - ソート文字列をキーにする、構成文字カウントをキーにする以外の実装は見当たらず | ||
| ## 解答 | ||
| - https://github.com/Shinkomori19/arai60/pull/3/files | ||
| - 構成文字の出現個数をカウントしたものをキーにする実装 | ||
| ```java | ||
| class Solution { | ||
| public List<List<String>> groupAnagrams(String[] strs) { | ||
| HashMap<String, List<String>> anagramKeyToAnagrams = new HashMap(); | ||
| for (String str : strs) { | ||
| String anagramKey = genAnagramKey(str); | ||
| anagramKeyToAnagrams | ||
| // 新規登録の場合は初期値として空の配列を登録 | ||
| .computeIfAbsent(anagramKey, (key) -> new ArrayList<>()) | ||
| .add(str); | ||
| } | ||
| return new ArrayList<>(anagramKeyToAnagrams.values()); | ||
| } | ||
|
|
||
| private String genAnagramKey(String unsorted) { | ||
| char[] chars = unsorted.toCharArray(); | ||
| int[] alphabetCount = new int[26]; | ||
| for (char c: chars) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 細かいのですが、for (char c : chars) でしょうか(:の左にスペース)。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 見落としてました、ありがとうございます! |
||
| //「-'a'」すると | ||
| // a → 0, b → 1, z → 26という具合になる | ||
| alphabetCount[c - 'a']++; | ||
| } | ||
| StringBuilder sb = new StringBuilder(); | ||
| for (int count : alphabetCount) { | ||
| sb.append("#").append(count); | ||
| } | ||
|
Comment on lines
+58
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Javaのことはあまり詳しくなく恐縮ですが、ここは[1,2,3]のような配列はmutableだからkeyにできないので、immutableな1#2#3という文字列に変換しているという理解でよいでしょうか?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 配列をkeyにすることは可能なのですが、配列の参照(アドレス)を元にhashを計算するので同一のObjectじゃないと同じような形をした配列でもMapから値を取り出せません。 Map<int[], String> map = new HashMap<>();
int[] key1 = {1, 2};
int[] key2 = {1, 2};
map.put(key1, "hello");
System.out.println(map.get(key1)); // hello
System.out.println(map.get(key2)); // nullThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<List<Integer>, List<String>> anagramKeyToAnagrams = new HashMap();
for (String str : strs) {
List<Integer> anagramKey = genAnagramKey(str);
anagramKeyToAnagrams
// 新規登録の場合は初期値として空の配列を登録
.computeIfAbsent(anagramKey, (key) -> new ArrayList<>())
.add(str);
}
return new ArrayList<>(anagramKeyToAnagrams.values());
}
private List<Integer> genAnagramKey(String unsorted) {
char[] chars = unsorted.toCharArray();
List<Integer> alphabetCount = new ArrayList<>();
for (char c: chars) {
//「-'a'」すると
// a → 0, b → 1, z → 26という具合になる
int index = c - 'a';
while (alphabetCount.size() <= index) {
alphabetCount.add(0);
}
alphabetCount.set(index, alphabetCount.get(index) + 1);
}
return alphabetCount;
}
}軽くJavaの実装を見たのですが、ArrayListだとハッシュ値の計算を要素から計算しているのでオブジェクトが異なってもhash値が一致するので上のコードだと動きますね。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ArrayListのハッシュ計算について意識したことがなかったです。 |
||
| return sb.toString(); | ||
| } | ||
| } | ||
| ``` | ||
| - 今回の入力では考慮不要だがサロゲートペアに配慮した実装も試してみる。これで絵文字や変な漢字がきても処理できる。 | ||
| ```java | ||
| class Solution { | ||
| public List<List<String>> groupAnagrams(String[] strs) { | ||
| HashMap<String, List<String>> sortedToAnagrams = new HashMap<>(); | ||
| for (String str : strs) { | ||
| String sorted = sortStringWithCodePoint(str); | ||
| sortedToAnagrams | ||
| .computeIfAbsent(sorted, (k) -> new ArrayList<>()) | ||
| .add(str); | ||
| } | ||
| return new ArrayList<>(sortedToAnagrams.values()); | ||
| } | ||
|
|
||
| private String sortStringWithCodePoint(String str) { | ||
| int[] codePoints = str.codePoints().toArray(); | ||
| Arrays.sort(codePoints); | ||
| StringBuilder sb = new StringBuilder(); | ||
| for (int codePoint : codePoints) { | ||
| sb.appendCodePoint(codePoint); | ||
| } | ||
| return sb.toString(); | ||
| } | ||
| } | ||
| ``` | ||
| # step3 3回ミスなく書く | ||
|
|
||
| ## 解答 | ||
| - step1と同様の実装 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 全体的に読みやすいなと感じました。 |
||
| ```java | ||
| class Solution { | ||
| public List<List<String>> groupAnagrams(String[] strs) { | ||
| Map<String, List<String>> sortedToAnagrams = new HashMap<>(); | ||
| for (String str : strs) { | ||
| String sorted = sortString(str); | ||
| sortedToAnagrams | ||
| .computeIfAbsent(sorted, (key -> new ArrayList<>())) | ||
| .add(str); | ||
| } | ||
| return new ArrayList<>(sortedToAnagrams.values()); | ||
| } | ||
|
|
||
| private String sortString(String str) { | ||
| char[] chars = str.toCharArray(); | ||
| Arrays.sort(chars); | ||
| return new String(chars); | ||
| } | ||
| } | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generateの意味だと思いますが、
genがどこまで一般的なのか自分はわからないのと、書く回数が多くないのでgenerateにすると思います。There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
親しんだ環境では一般的だったので、半ば無意識でした。
ご指摘ありがとうございます!