-
Notifications
You must be signed in to change notification settings - Fork 0
373. Find K Pairs with Smallest Sums #17
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
Changes from all commits
aace3dd
3cde121
998ec1c
d62e36a
32ccdcd
3592ed3
1691631
d4777c9
3ecf75e
23db7ca
02666d1
ce12c50
71568b7
a64480b
8f11027
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,44 @@ | ||
| # 373. Find K Pairs with Smallest Sums | ||
|
|
||
| ## step1 | ||
| 時間計算量: O(klogk), 空間計算量: O(k) | ||
| 全探索しか思い浮かばず、ACできなかった。 | ||
| 回答をみて理解してその通りに実装(変数名のリネームはおこなった。) | ||
| 大まかな思考の流れは以下の通り | ||
| 1, 単純に全探索→ソートすると計算量がよくないので、改善のためにどのように比較をするかを考える | ||
| 2, 実際に比較をするのは、最小のペア(nums1[index1], nums2[index2])を基準に考えると、次の最小値は(nums1[index1 + 1], nums2[index2], nums1[index1], nums2[index2 + 1])かもしくは、この以前のステップでのこったもののどれかとなる。 | ||
| 3, 上記で以前のステップでのこったものを実現すること、常にソートされた状態でいることを考慮してHeapを使うという流れとなる。 | ||
| 4, あとは追加の際に重複をさけるため、Setを用意して重複のIndexペアは弾くようにする。 | ||
|
|
||
| ## step2 | ||
| 他の人の実装を参考に実装した。 | ||
| ### step2-1 | ||
| 参考:https://github.com/seal-azarashi/leetcode/pull/10/files | ||
| 根本的な解法はstep1と同じだが、PriorityQueueにいれる中身を変えて、変数を少なくしたタイプ。変数宣言での記述量は増えるものの、繰り返しの部分は余計な合計などもなくわかりやすいかなとおもった。 | ||
|
|
||
| ### step2-2 | ||
| 参考:[https://github.com/seal-azarashi/leetcode/pull/10/files](https://github.com/kazukiii/leetcode/pull/11/files) | ||
| 実装していて、indexまわりをまとめて独自で定義したほうが見やすいなあとおもっていて同様のコメントが上記のPRでもあったので、独自定義する方針でも実装してみた。 | ||
|
|
||
| ## メモ | ||
| Loopの表現についてfor, whileの議論が他のPRのコメントでもあったが、宣言的か手続的のどちらがいいかというものがあり、今回の問題だと個人的にはどちらでもそこまで変わらないかなと思ったが問題や条件によってはどちらが自然かというのを常に意識したい。 | ||
| また問題文の制約次第ではループのなかでエラーとなる可能性があることも意識したい。 | ||
| https://github.com/sakupan102/arai60-practice/pull/11#discussion_r1622031840 | ||
| https://github.com/fhiyo/leetcode/pull/13/files | ||
|
|
||
| ## step3 | ||
| いただいたコメントを元に修正した。 | ||
| ### step3-1 | ||
| アルゴリズムの修正を行なった。 | ||
| ・2つの配列について片方の配列のIndexしか動かさない | ||
| ・動かす方のindex = 0の時のみもう片方の配列のについてその配列のIndex+1の要素をQueueに追加 | ||
| することで重複がないようにおこなうことができる。 | ||
|
|
||
| ### step3-2 | ||
| 独自クラスの定義のし直し、および共通ロジックを関数として外出しした。 | ||
| 修正を行うと途端にどこが共通化されているのか、どこが無駄な処理になるのかがぼやけるので、全体の処理を頭に置きながら共通化部分をしっかり頭で描いてからコードにうつるように癖づけないといけないと思った。 | ||
| また、HashSetに独自クラスのオブジェクトをいれるときに、仕組みとしてどのように一致判定を行なっているかについて気になったので以下にまとめる。 | ||
|
|
||
| ・HashSetではAbstractSetをimplementしており、equalsとhashCodeを使ってObjectの一致判定をしている。 | ||
| ・classは暗黙的にObjectクラスを継承しているのでequalsとhashCodeは必ずもっている。 | ||
| ・独自クラスでかつ一致判定をカスタムしたい時は上記をOverrideする必要がある。 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| class Solution { | ||
| public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { | ||
| int length1 = nums1.length; | ||
| int length2 = nums2.length; | ||
| List<List<Integer>> kSmallestPairs = new ArrayList<>(); | ||
| Set<Pair<Integer, Integer>> visited = new HashSet<>(); | ||
|
|
||
| PriorityQueue<int[]> minSums = new PriorityQueue<>((a, b) -> a[0] - b[0]); | ||
| minSums.add(new int[] {nums1[0] + nums2[0], 0, 0}); | ||
| visited.add(new Pair<Integer, Integer>(0, 0)); | ||
|
|
||
| while(kSmallestPairs.size() < k) { | ||
| int[] currentMinPair = minSums.poll(); | ||
| int index1 = currentMinPair[1]; | ||
| int index2 = currentMinPair[2]; | ||
| kSmallestPairs.add(List.of(nums1[index1], nums2[index2])); | ||
| if (index1 + 1 < length1 && !visited.contains(new Pair<Integer, Integer>(index1 + 1, index2))) { | ||
|
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. (index1 + 1, index2)の要素を入れるのは index2が0のときのみ、とすると重複が発生せずvisitedが不要になりそうです。 if (index2 == 0 && index1 + 1 < length1) { |
||
| minSums.add(new int[] {nums1[index1 + 1] + nums2[index2], index1 + 1, index2}); | ||
| visited.add(new Pair<Integer, Integer>(index1 + 1, index2)); | ||
| } | ||
| if (index2 + 1 < length2 && !visited.contains(new Pair<Integer, Integer>(index1, index2 + 1))) { | ||
| minSums.add(new int[] {nums1[index1] + nums2[index2 + 1], index1, index2 + 1}); | ||
| visited.add(new Pair<Integer, Integer>(index1, index2 + 1)); | ||
| } | ||
| } | ||
| return kSmallestPairs; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| class Solution { | ||
| public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { | ||
| int length1 = nums1.length; | ||
| int length2 = nums2.length; | ||
| List<List<Integer>> kSmallestPairs = new ArrayList<>(); | ||
| Set<Pair<Integer, Integer>> visited = new HashSet<>(); | ||
|
|
||
| PriorityQueue<int[]> minSortedPairs = new PriorityQueue<>((a, b) -> (nums1[a[0]] + nums2[a[1]]) - (nums1[b[0]] + nums2[b[1]])); | ||
| minSortedPairs.add(new int[] {0, 0}); | ||
| visited.add(new Pair<Integer, Integer>(0, 0)); | ||
|
|
||
| while(kSmallestPairs.size() < k) { | ||
| int[] currentMinPair = minSortedPairs.poll(); | ||
| int index1 = currentMinPair[0]; | ||
| int index2 = currentMinPair[1]; | ||
| kSmallestPairs.add(List.of(nums1[index1], nums2[index2])); | ||
| if (index1 + 1 < length1 && !visited.contains(new Pair<Integer, Integer>(index1 + 1, index2))) { | ||
| minSortedPairs.add(new int[] {index1 + 1, index2}); | ||
| visited.add(new Pair<Integer, Integer>(index1 + 1, index2)); | ||
| } | ||
| if (index2 + 1 < length2 && !visited.contains(new Pair<Integer, Integer>(index1, index2 + 1))) { | ||
| minSortedPairs.add(new int[] {index1, index2 + 1}); | ||
| visited.add(new Pair<Integer, Integer>(index1, index2 + 1)); | ||
| } | ||
| } | ||
| return kSmallestPairs; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| class Solution { | ||
| public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { | ||
| int length1 = nums1.length; | ||
| int length2 = nums2.length; | ||
| List<List<Integer>> kSmallestPairs = new ArrayList<>(); | ||
| Set<Pair<Integer, Integer>> visited = new HashSet<>(); | ||
|
|
||
| PriorityQueue<SumPair> minSortedPairs = new PriorityQueue<>((a, b) -> (a.sum - b.sum)); | ||
| minSortedPairs.add(new SumPair(nums1, 0, nums2, 0)); | ||
| visited.add(new Pair<Integer, Integer>(0, 0)); | ||
|
|
||
| for(int i = 0; i < k; i++) { | ||
| SumPair currentMinPair = minSortedPairs.poll(); | ||
| int index1 = currentMinPair.indice.getKey(); | ||
| int index2 = currentMinPair.indice.getValue(); | ||
| kSmallestPairs.add(List.of(currentMinPair.elements.getKey(), currentMinPair.elements.getValue())); | ||
|
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. List.of(currentMinPair.elements.getKey(), currentMinPair.elements.getValue())これ SumPair のメソッドにしてもいいんじゃないですか。 ほかも色々とメンバーにしてもいいかもしれませんね。 |
||
| if (index1 + 1 < length1 && !visited.contains(new Pair<Integer, Integer>(index1 + 1, index2))) { | ||
| minSortedPairs.add(new SumPair(nums1, index1 + 1, nums2, index2)); | ||
| visited.add(new Pair<Integer, Integer>(index1 + 1, index2)); | ||
| } | ||
| if (index2 + 1 < length2 && !visited.contains(new Pair<Integer, Integer>(index1, index2 + 1))) { | ||
| minSortedPairs.add(new SumPair(nums1, index1, nums2, index2 + 1)); | ||
| visited.add(new Pair<Integer, Integer>(index1, index2 + 1)); | ||
| } | ||
| } | ||
|
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. ここのところ、素直に日本語で表現すると、
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. ありがとうございます!共通処理の部分は別関数に切り出そうとおもいます |
||
| return kSmallestPairs; | ||
| } | ||
| } | ||
|
|
||
| class SumPair { | ||
| int sum; | ||
| Pair<Integer, Integer> elements; | ||
|
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. elements ではなく、nums1, nums2 への参照を持つのも一つでしょうか。
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. indexだけでことたりそうかなともおもいましたので、シンプルに合計値とIndexだけをもつようにしました |
||
| Pair<Integer, Integer> indice; | ||
|
|
||
| SumPair(int[] nums1, int index1, int[] nums2, int index2) { | ||
| this.sum = nums1[index1] + nums2[index2]; | ||
| this.elements = new Pair(nums1[index1], nums2[index2]); | ||
| this.indice = new Pair(index1, index2); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| class Solution { | ||
| public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { | ||
| int length1 = nums1.length; | ||
| int length2 = nums2.length; | ||
| List<List<Integer>> kSmallestPairs = new ArrayList<>(); | ||
|
|
||
| PriorityQueue<int[]> minSums = new PriorityQueue<>((a, b) -> a[0] - b[0]); | ||
| minSums.add(new int[] { nums1[0] + nums2[0], 0, 0 }); | ||
|
|
||
| while (kSmallestPairs.size() < k) { | ||
| int[] totalAndIndexes = minSums.poll(); | ||
| int index1 = totalAndIndexes[1]; | ||
| int index2 = totalAndIndexes[2]; | ||
| kSmallestPairs.add(List.of(nums1[index1], nums2[index2])); | ||
| if (index2 == 0 && index1 + 1 < length1) { | ||
| minSums.add(new int[] { nums1[index1 + 1] + nums2[index2], index1 + 1, index2 }); | ||
| } | ||
| if (index2 + 1 < length2) { | ||
| minSums.add(new int[] { nums1[index1] + nums2[index2 + 1], index1, index2 + 1 }); | ||
| } | ||
| } | ||
| return kSmallestPairs; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| class Solution { | ||
| int[] nums1; | ||
| int[] nums2; | ||
|
|
||
| public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { | ||
| this.nums1 = nums1; | ||
| this.nums2 = nums2; | ||
| List<List<Integer>> kSmallestPairs = new ArrayList<>(); | ||
| Set<IndexPair> visited = new HashSet<>(); | ||
| PriorityQueue<IndexPair> minSortedPairs = new PriorityQueue<>((a, b) -> (a.sum - b.sum)); | ||
| IndexPair firstPair = new IndexPair(0, 0, nums1[0] + nums2[0]); | ||
| minSortedPairs.add(firstPair); | ||
| visited.add(firstPair); | ||
|
|
||
| for(int i = 0; i < k; i++) { | ||
| IndexPair currentMinPair = minSortedPairs.poll(); | ||
| int index1 = currentMinPair.index1; | ||
| int index2 = currentMinPair.index2; | ||
| kSmallestPairs.add(List.of(nums1[index1], nums2[index2])); | ||
| insertPairIfNeeded(minSortedPairs, visited, index1 + 1, index2); | ||
| insertPairIfNeeded(minSortedPairs, visited, index1, index2 + 1); | ||
| } | ||
| return kSmallestPairs; | ||
| } | ||
|
|
||
| private void insertPairIfNeeded(PriorityQueue<IndexPair> queue, Set<IndexPair> visited, int pos1, int pos2) { | ||
| int len1 = nums1.length; | ||
| int len2 = nums2.length; | ||
| if (len1 <= pos1 || len2 <= pos2) { | ||
| return; | ||
| } | ||
| IndexPair newPair = new IndexPair(pos1, pos2, nums1[pos1] + nums2[pos2]); | ||
| if (visited.contains(newPair)) { | ||
| return; | ||
| } | ||
| queue.add(newPair); | ||
| visited.add(newPair); | ||
| } | ||
| } | ||
|
|
||
| class IndexPair { | ||
| int sum; | ||
| int index1; | ||
| int index2; | ||
|
|
||
| IndexPair(int index1, int index2, int sum) { | ||
| this.index1 = index1; | ||
| this.index2 = index2; | ||
| this.sum = sum; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| IndexPair other = (IndexPair) o; | ||
| return other.index1 == index1 && other.index2 == index2; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(index1, index2); | ||
| } | ||
| } |
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.
currentMinPairといいつつ実際の要素数が3つなのは少し気になりました。
良い名前思いつかないんですがtotalAndIndexesとかですかね...