-
Notifications
You must be signed in to change notification settings - Fork 0
Create 1. Two Sum.md #23
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,103 @@ | ||
| # [1. TWO SUM](https://leetcode.com/problems/two-sum/description/) | ||
|
|
||
| ## Step1 | ||
| ### 問題意図の考察 | ||
|
|
||
| - 整数配列 numsと整数 targetに対して、合計がtargetになる数のindexを返す | ||
| - 問題文にある条件の確認 | ||
| 1. 必ずちょうど一つの解が存在する | ||
| 2. 同じ要素を返してはいけない | ||
| 3. インデックスを返す順番はどちらでもいい | ||
| 4. 1.exactly one solution -> 「複数解をどう扱うか」を考えなくでOK、つまり即return | ||
|
|
||
| - 制約の確認 | ||
| 1. 配列numsの長さ、要素数は、2 ~ 10,000 -> 最大要素数は10,000で単純ループだと1億回 | ||
| 2. 配列numsの各要素nums[i]は、-1,000,000,000 ~ +1,000,000,000 | ||
| -> 大きな数や小さな数が出てくることもあるから値に依存したアルゴリズムは不向きかな | ||
| -> C++ int(32bits)は、おおよそ-2,174,483,648 ~ -2,174,483,647、nums[i]は+-10^9なので合計もintの範囲内でintOK。オーバーフローはしない,問題文通り | ||
| 3. targetの値も、+-10^9の間、intOK | ||
| - ここでは「1億回の比較O(n^2)」くらいだと、0.05 ~ 0.3秒前後でそんなに時間が掛からないが、よりベターな方法を探したい。 | ||
| - ペアを探す。つまり、補数を探す。O(1)での探索 | ||
| -> nums[i] + nums[j] = target | ||
| -> nums[j] = target - nums[i] | ||
| - 値ではなく、indexで返せるか | ||
|
|
||
| ### 解法を考える。 | ||
| - 整数配列nums、整数targetで、nums[i] + nums[j] = targetとなるインデックスi, jを探す | ||
| - 問題文から補数を探す、今回はハッシュマップ unordered_mapで良さそう | ||
| - 整理すると、 | ||
| 1. 配列を左から順番に要素をみる | ||
| 2. nums[j] = target - nums[i] はあるか探索 | ||
| 3. ある時、あったよ | ||
| 4. ない時、nums[i]は見たよと記録して次 | ||
|
|
||
|
|
||
| 初回の回答 | ||
| ```cpp | ||
| #include <unordered_map> | ||
| #include <vector> | ||
|
|
||
|
|
||
| class Solution { | ||
| public: | ||
| std::vector<int> twoSum(std::vector<int>& nums, int target) { | ||
| std::unordered_map<int, int> num_to_index; | ||
| for (int i = 0; i < nums.size(); ++i) { | ||
| int complement = target - nums[i]; | ||
| if (num_to_index.count(complement)) { | ||
| return std::vector<int>{num_to_index[complement], i}; | ||
|
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. initializer_list をコンストラクターにとる引数でインスタンス化して返すことができますので、 return {num_to_index[complement], i};のほうがシンプルで良いと思います。
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. @nodchip
把握できてなかったので、referenceをじっくり読んで次回書けるようにしたいと思います。 |
||
| } | ||
| num_to_index[nums[i]] = i; | ||
| } | ||
| return std::vector<int>{}; | ||
| } | ||
| }; | ||
|
|
||
| ``` | ||
|
|
||
|
|
||
| ## Step2 | ||
| - 初回同じキーに対してハッシュを2回使用しているので、find()という書き方も | ||
| - find rerturn に対しては、{}を返せる | ||
| - 「符号付きと符号なしの比較」あたりの修正。気づかなかった。 | ||
|
|
||
| ```cpp | ||
| #include <unordered_map> | ||
| #include <vector> | ||
|
|
||
|
|
||
| class Solution { | ||
| public: | ||
| std::vector<int> twoSum(std::vector<int>& nums, int target) { | ||
|
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. ここのnumsはconst参照にした方が良いかなと思います。 |
||
| std::unordered_map<int, int> num_to_index; | ||
| for (int i = 0; i < static_cast<int>(nums.size()); ++i) { | ||
| int complement = target - nums[i]; | ||
| auto it = num_to_index.find(complement); | ||
| if (it != num_to_index.end()) { | ||
|
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. C++20以降であれば、 とした方が実際のコードの目的と合っているので読みやすいかと思います。 https://cpprefjp.github.io/reference/unordered_map/unordered_map/contains.html
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. @ntanaka1984 |
||
| return std::vector<int>{it->second, i}; | ||
| } | ||
| num_to_index[nums[i]] = i; | ||
| } | ||
| return {}; | ||
| } | ||
| }; | ||
|
|
||
| ``` | ||
|
|
||
| - map&unordered_map復習(以下リンク) | ||
| - 選択の基準としては、要素の数・順序・セキュリティ・最悪計算量・小さいところでのメモリ使用量あたり | ||
| - https://github.com/ryosuketc/leetcode_grind75/pull/1/commits/2c5161514b4561a34193852a2a218603b35ca734#r2249075780 | ||
| - https://chromium.googlesource.com/chromium/src/+/master/base/containers/README.md#Map-and-set-selection-Usage-advice | ||
| - https://stackoverflow.com/questions/3902644/choosing-between-stdmap-and-stdunordered-map | ||
|
|
||
| ### 参考GitHub | ||
| - https://github.com/ryosuketc/leetcode_grind75/pull/1/commits/2c5161514b4561a34193852a2a218603b35ca734 | ||
| - https://github.com/Ryotaro25/leetcode_first60/pull/12/commits/9c80068466e83724dc9004bca374e26f2b130b95 | ||
|
|
||
|
|
||
| ## Step3 | ||
| 6min | ||
| 7min | ||
| 5min | ||
| 5min | ||
| 5min | ||
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.
std::unordered_map (std::unordered_set) は std::map (std::set) より insert() が遅いようです。また、要素数が少ない時は std::unordered_map (std::unordered_set) のほうがメモリ使用量が大きいようです。
https://chromium.googlesource.com/chromium/src/+/HEAD/base/containers/README.md#std_unordered_map-and-std_unordered_set
https://groups.google.com/a/chromium.org/g/chromium-dev/c/rdxOHKzQmRY?pli=1
用途に応じて適切に使い分けるのが理想的です。一方、処理時間があまり問題とならない場合に、データ構造の選択に時間をかけるのは不適切です。このあたりはチームの平均的なやり方に合わせることをおすすめします
Uh oh!
There was an error while loading. Please reload this page.
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.
@nodchip
コメント頂きありがとうございます。
ドキュメントもう少しじっくり読んでみます。
適切な評価をして、使い分けれるように今はじっくりと考えていきたいと思いますが、
この辺りも頭の片隅に記憶しておきます。