Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions 49/49. Group Anagrams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# [49. Group Anagrams](https://leetcode.com/problems/group-anagrams/description/)

## Step1
### 問題意図の考察
- 問題文の確認
 * Anagramsをグループ化せよ。という問題
 * アナグラム->同じ文字を同じ数保持している. よって、文字列をソートしてabcd順にするとkey
 * このkeyをまとめて分類

- 制約の確認
1. 1 <= strs.length <= 10^4
* 文字列最大10^4(10,000), O(N^2)の時、10^8回(1億) 計算量は、O(N * 何か)程度だといいかな
2. 0 <= strs[i].length <= 100
* strs[i].length = i番目の文字列の長さ(文字数)
* つまり、0~100文字以内で、空文字もある
* 最大: 10^4 * 100 = 10^6 なので、ソート or カウントしても間に合いそう
3. strs[i] consists of lowercase English letters.
* strs[i]は、英小文字のみ
* 26文字
* 他の文字は考慮しなくて良さそう

### 解法を考える。
- 文字列をソートして、keyを作成する
- keyをカウント&グループ化
- 同じものは、分類

- 配列の配列というものが書いたことがなく混乱してしまった、冒頭で答えを見る。慣れていきたい。

初回の回答
```cpp
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <string>

class Solution {
public:
std::vector<std::vector<std::string> > groupAnagrams(std::vector<std::string>& strs) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C++11 以降 >> のあいだにスペースを空けなくて済むようになっています。スペースを消すことをおすすめします。

https://cpprefjp.github.io/lang/cpp11/right_angle_brackets.html

C++11からは、 vector<basic_string> のように、2つ以上連続する右山カッコの間に、スペースを入力する必要がなくなった。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nodchip
コメントありがとうございます。
こちら確認不足でした。一読しておきます。

std::unordered_map<std::string, std::vector<std::string> > groups;
for (const std::string& s : strs) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (const auto& s : strs) {

のほうがシンプルだと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nodchip
ご指摘ありがとうございます。
こちらの方が明示的かと思いましたが、これくらいであれば

for (const auto& s : strs) {

の方が読みやすいかもしれないですね。
ありがとうございます。

std::string key = s;
std::sort(key.begin(), key.end());
groups[key].push_back(s);
}

std::vector<std::vector<std::string> > result;
result.reserve(groups.size());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reserve() をすることにより、あらかじめ必要な要素数分のメモリを確保し、 push_back() 中のメモリの再確保を避けることができるのですが、その効果が十分かどうかは計測してみないと何とも言えません。処理時間に対する要求を考慮し、シビアでない場合、 コードをシンプルにするため、reserve() を呼び出さないほうがよい場合もあると思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nodchip
ありがとうございます。
効果の測定まで検証できておりませんでした。chronoで時間を測ってみたいと思います。

for (auto& entry : groups) {
result.push_back(std::move(entry.second));
}
return result;
}
};

```
模範回答
```cpp
```
### コメント

## Step2
- 今回は英小文字しか出現しないが、 それ以外が出た時の対処も考えておきたい。
- ドキュメントの確認・気になったところ
1. std::vector (push_back / reserve / size)
* https://en.cppreference.com/w/cpp/container/vector.html
* https://en.cppreference.com/w/cpp/container/vector/push_back
* https://en.cppreference.com/w/cpp/container/vector/reserve
* https://en.cppreference.com/w/cpp/container/vector/size
2. std::unordered_map ハッシュマップ
* https://en.cppreference.com/w/cpp/container/unordered_map.html
* https://en.cppreference.com/w/cpp/container/unordered_map/operator_at
3. for (auto& x : container)
* https://en.cppreference.com/w/cpp/language/range-for.html
- 他の方のコード
* https://github.com/nktr-cp/leetcode/pull/13/commits/f1d09d3f5d201aa096e53824affbc11fa260a46a
* https://github.com/Ryotaro25/leetcode_first60/pull/13/commits/2416b565cd8a2a983b8cab3543d1b0d32dbc4649#diff-f08ab28ba7826a9f3d22cb94b7e24009a629a8e4212261d33183da905119b247
-> https://github.com/Ryotaro25/leetcode_first60/pull/13/commits/2416b565cd8a2a983b8cab3543d1b0d32dbc4649#r1665235074
-> sorted_to_group / group_anagrams という命名
* unordered_map<string, vector<string>> の中身の確認
```cpp
entry.first → "aet"
entry.second → ["eat", "tea", "ate"]

entry.first → "ant"
entry.second → ["tan", "nat"]

entry.first → "abt"
entry.second → ["bat"]

```
* マップキーと値の関係の理解ができた

```cpp
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <string>

class Solution {
public:
std::vector<std::vector<std::string> > groupAnagrams(std::vector<std::string>& strs) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

非const参照で受け取ると変更の可能性があることを呼び出し側は考慮することになるので、内部で変更をしないのであればconstをつけてもよいかと思います。

std::unordered_map<std::string, std::vector<std::string> > groups;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

なにをキーにしてグループをまとめているかの情報が後を読まないとわからないので、sorted_str_to_groups(sorted_str_to_anagramsなど)くらいでもよいかなと思いました。

for (const std::string& word : strs) {
std::string key = word;
std::sort(key.begin(), key.end());
groups[key].push_back(s);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sではなくwordでしょうか。

}

std::vector<std::vector<std::string> > result;
result.reserve(groups.size());
for (auto& entry : groups) {
result.push_back(std::move(entry.second));
}
return result;
}
};

```

## Step3
1. 10min
2. 9min
3. 6min
4. 5min
5. 5min