Skip to content
Open
Show file tree
Hide file tree
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
11 changes: 11 additions & 0 deletions 0373-find-k-pair-with-smallest-sums/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### step1

最初nums1, nums2の組み合わせを全探索してpriority_queueに入れて、小さい順に取り出す方法を思いついてTLE思想だと思ったが、それ以外思いつかなかったのでそれで実装。Naoto Iwaseさんのコードを参考に修正。nums1はindex 0のものとnums2はk個目までの和を最初にpriority_queueに入れておいて、popするたびにnums1のindexをインクリメントしたものをpriority_queueにpushするという実装。これで時間計算量はO(nums1 * nums2)からO(k)に落ちると思う。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちらのコメントを参照されることをお勧めいたします。
Yuto729/leetcode#16 (comment)


### step2

特に変更点なし

### step3

3回通すまで書き直し。
54 changes: 54 additions & 0 deletions 0373-find-k-pair-with-smallest-sums/step1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 最初このコードを書いてTLE

class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
priority_queue<pair<int, vector<int>>> kth_smallest;
for (int num1 : nums1) {
for (int num2 : nums2) {
kth_smallest.push({num1 + num2, { num1, num2 }});
if (kth_smallest.size() > k) kth_smallest.pop();
}
}
vector<vector<int>> answer;
while (!kth_smallest.empty()) {
answer.push_back(kth_smallest.top().second);
kth_smallest.pop();
}
return answer;
}
};

// Naoto Iwaseさんのコードを参考に修正したもの

class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
priority_queue<
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

pair<int, pair<int,int>> は、どこに何が入っているのか分かりにくく感じました。 struct を定義し、 operator<() を定義してあげたほうが、読み手にとって読みやすくなると思います。
スコープが十分に短ければ、pair<int, pair<int,int>> でも問題ないと思います。

pair<int, pair<int,int>>,
vector<pair<int, pair<int,int>>>,
greater<>
> smallest;

for (int j = 0; j < nums2.size() && j < k; ++j) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

この方法だと、どのペアを既に追加したかを記録する必要がなくなってスマートですね。
しかし、面接で緊張している時にこの方法を思いつくのは難しそうだなと思いました。

smallest.push({nums1[0] + nums2[j], {0, j}});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

std::pair には、要素を引数に取るコンストラクターがあります。これを利用し、 emplace() で std::pair に格納される要素を直接渡して追加しても良いと思います。

smallest.emplace(nums1[0] + nums2[j], {0, j});

}

vector<vector<int>> answer;

while (!smallest.empty() && answer.size() < k) {
auto [sum, nums] = smallest.top();
smallest.pop();
int num1 = nums.first;
int num2 = nums.second;

answer.push_back({nums1[num1], nums2[num2]});

if (num1 + 1 < nums1.size()) {
smallest.push({nums1[num1 + 1] + nums2[num2], {num1 + 1, num2}});
}
Comment on lines +46 to +49
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

num1 + 1が3回出現しているので変数にまとめたいと思いました。変数名next_num1としてみたのですが、あまり良い変数名ではないかもしれません。重複するコードの内、意味が同じものであれば変数にまとめることで、可読性や保守性を向上できるという感覚です。

Suggested change
if (num1 + 1 < nums1.size()) {
smallest.push({nums1[num1 + 1] + nums2[num2], {num1 + 1, num2}});
}
int next_num1 = num1 + 1;
if (next_num1 < nums1.size()) {
smallest.push({nums1[next_num1] + nums2[num2], {next_num1, num2}});
}

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.

たしかに3回書いてるので変数にしてもいいかもしれないですね。

}

return answer;
}
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

step2,3と比べ、こちらの改行があるコードスタイルの方が読みやすいと感じました。変数の宣言、操作を行うコードが適切にグループ分けされているので読みやすいという感覚です。

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.

たしかに改行は多少はあった方が読みやすいかもしれないです。

20 changes: 20 additions & 0 deletions 0373-find-k-pair-with-smallest-sums/step2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<>> smallest;
for (int i = 0; i < nums2.size() && i < k; i++) {
smallest.push({nums1[0] + nums2[i], {0, i}});
}
vector<vector<int>> answer;
while (!smallest.empty() && answer.size() < k) {
auto [sum, nums] = smallest.top();
smallest.pop();
int num1 = nums.first, num2 = nums.second;
answer.push_back({nums1[num1], nums2[num2]});
if (num1 + 1 < nums1.size()) {
smallest.push({nums1[num1 + 1] + nums2[num2], {num1 + 1, num2}});
}
}
return answer;
}
};
21 changes: 21 additions & 0 deletions 0373-find-k-pair-with-smallest-sums/step3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<>> smallest;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3つ要素を含有するのであればtuple<int, int, int> か structを作るのも良いのかと思いました。

for (int i = 0; i < nums2.size(); i++) {
smallest.push({nums1[0] + nums2[i], {0, i}});
}
vector<vector<int>> answer;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

answer.reserve(k)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@austyhooong さん
reserve() を呼び出すべきかどうかについて、過去に複数のレビューコメントが書かれています。無条件に reserve() を呼び出すことを促すのではなく、過去のレビューコメントを勘案したうえで、呼び出すべきかどうかについてコメントを書かれることをお勧めいたします。

while (!smallest.empty() && answer.size() < k) {
auto [sum, nums] = smallest.top();
smallest.pop();
int num1 = nums.first;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

auto [num1, num2] = nums;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@austyhooong さん
レビューコメントにコードスニペットだけを書くのは、やや不躾なように感じました。「おすすめします」といたフレーズを添えると、語調が和らぎ、読み手に取って不快感を与えないのではないかと思います。

int num2 = nums.second;
answer.push_back({nums1[num1], nums2[num2]});
if (num1 + 1 < nums1.size()) {
smallest.push({nums1[num1 + 1] + nums2[num2], {num1 + 1, num2}});
}
}
return answer;
}
};