Skip to content

Commit afba9a0

Browse files
authored
Merge pull request #25 from colorbox/373
373. Find K Pairs with Smallest Sums
2 parents beaeff2 + 6d393cd commit afba9a0

File tree

10 files changed

+446
-0
lines changed

10 files changed

+446
-0
lines changed

373/step1.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
1時間以上
3+
4+
Time: O( log(max(nums1,nums2)) * n log(m) )
5+
Space: O( k )
6+
n = nums1.size()
7+
m = nums2.size()
8+
9+
nums1,nums2のすべてのペアを検証すると時間が足りないので、それを補う方法を考える。
10+
ペアの数がk個以下となるような値Lを二分探索で探す。
11+
合計値がL以下のペアをpriority_queueにいれて最小k個のペアを探す。
12+
・二分探索での桁溢れ
13+
・同値のペアが大量に作成される
14+
などの問題を都度修正したら過アンリ時間がかかってしまったがかろうじてパスはしたものの
15+
色々と筋悪な回答なのでstep2以降で修正する。
16+
17+
*/
18+
class Solution {
19+
public:
20+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
21+
long long int left = nums1.front() + nums2.front();
22+
long long int right = nums1.back() + nums2.back() + 1;
23+
long long int mid;
24+
while (left + 1 < right) {
25+
mid = left + (right - left) / 2;
26+
int count = count_less_pairs(nums1, nums2, mid, k);
27+
if (count >= k) {
28+
right = mid;
29+
} else {
30+
left = mid;
31+
}
32+
}
33+
34+
priority_queue<SumPair> sum_pairs;
35+
for (int num1 : nums1) {
36+
for (int num2 : nums2) {
37+
if (num1 + num2 > right) {
38+
break;
39+
}
40+
sum_pairs.push({num1 + num2, {num1, num2}});
41+
if (sum_pairs.size() > k) {
42+
sum_pairs.pop();
43+
if (num1 + num2 == sum_pairs.top().sum) {
44+
break;
45+
}
46+
}
47+
}
48+
}
49+
50+
vector<vector<int>> answer;
51+
while (!sum_pairs.empty()) {
52+
answer.push_back(sum_pairs.top().pair);
53+
sum_pairs.pop();
54+
}
55+
return answer;
56+
}
57+
private:
58+
59+
struct SumPair {
60+
int sum;
61+
vector<int> pair;
62+
63+
bool operator< (const SumPair& other) const {
64+
return sum < other.sum;
65+
}
66+
};
67+
68+
int count_less_pairs(vector<int> nums1, vector<int>nums2, int num, int limit) {
69+
int count_sum = 0;
70+
for (int num1 : nums1) {
71+
auto it = upper_bound(nums2.begin(), nums2.end(), num - num1);
72+
if (it == nums2.end()) {
73+
count_sum += nums2.size();
74+
if (count_sum > limit) {
75+
return limit;
76+
}
77+
continue;
78+
}
79+
int count = it - nums2.begin();
80+
count_sum += count;
81+
}
82+
return count_sum;
83+
}
84+
};

373/step1_fix.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
step1 after review
3+
*/
4+
5+
class Solution {
6+
public:
7+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
8+
int64_t left = nums1.front() + nums2.front();
9+
int64_t right = nums1.back() + nums2.back() + 1;
10+
while (left < right) {
11+
int64_t mid = left + (right - left) / 2;
12+
int count = count_less_pairs(nums1, nums2, mid, k);
13+
if (count >= k) {
14+
right = mid;
15+
} else {
16+
left = mid + 1;
17+
}
18+
}
19+
20+
int max_sum = left;
21+
priority_queue<SumPair> sum_pairs;
22+
for (int num1 : nums1) {
23+
for (int num2 : nums2) {
24+
if (num1 + num2 > max_sum) {
25+
break;
26+
}
27+
sum_pairs.push({num1 + num2, {num1, num2}});
28+
if (sum_pairs.size() > k) {
29+
sum_pairs.pop();
30+
if (num1 + num2 == sum_pairs.top().sum) {
31+
break;
32+
}
33+
}
34+
}
35+
}
36+
37+
vector<vector<int>> answer;
38+
while (!sum_pairs.empty()) {
39+
answer.push_back(sum_pairs.top().pair);
40+
sum_pairs.pop();
41+
}
42+
return answer;
43+
}
44+
private:
45+
46+
struct SumPair {
47+
int sum;
48+
vector<int> pair;
49+
50+
bool operator< (const SumPair& other) const {
51+
return sum < other.sum;
52+
}
53+
};
54+
55+
int count_less_pairs(vector<int> nums1, vector<int>nums2, int num, int limit) {
56+
int num_pairs = 0;
57+
for (int num1 : nums1) {
58+
auto it = upper_bound(nums2.begin(), nums2.end(), num - num1);
59+
num_pairs += distance(nums2.begin(), it);
60+
if (num_pairs > limit) {
61+
return limit;
62+
}
63+
}
64+
return num_pairs;
65+
}
66+
};

373/step2.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
他の方の回答を参考にやり直したもの
3+
nums1,nums2のインデックスのペアをダイクストラ法っぽく処理していく
4+
Time: O(k logk)
5+
Space: O(k)
6+
*/
7+
class Solution {
8+
public:
9+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
10+
priority_queue<SumIndex, vector<SumIndex>, greater<SumIndex>> sum_index;
11+
set<vector<int>> visited;
12+
vector<vector<int>> answer;
13+
sum_index.push({nums1[0] + nums2[0], {0, 0}});
14+
while (answer.size() < k) {
15+
int i = sum_index.top().index[0];
16+
int j = sum_index.top().index[1];
17+
sum_index.pop();
18+
answer.push_back({nums1[i], nums2[j]});
19+
if (i + 1 < nums1.size() && !visited.contains({i + 1, j})) {
20+
sum_index.push({nums1[i + 1] + nums2[j], {i + 1, j}});
21+
visited.insert({i + 1, j});
22+
}
23+
if (j + 1 < nums2.size() && !visited.contains({i, j + 1})) {
24+
sum_index.push({nums1[i] + nums2[j + 1], {i, j + 1}});
25+
visited.insert({i, j + 1});
26+
}
27+
}
28+
29+
return answer;
30+
}
31+
32+
private:
33+
struct SumIndex {
34+
int sum;
35+
vector<int> index;
36+
37+
bool operator> (const SumIndex& other) const {
38+
return sum > other.sum;
39+
}
40+
};
41+
};

373/step2_2.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
step2 after review
3+
*/
4+
class Solution {
5+
public:
6+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
7+
priority_queue<SumIndex> sum_index;
8+
set<vector<int>> visited;
9+
vector<vector<int>> answer;
10+
sum_index.push({nums1[0] + nums2[0], {0, 0}});
11+
while (answer.size() < k) {
12+
int i = sum_index.top().index[0];
13+
int j = sum_index.top().index[1];
14+
sum_index.pop();
15+
answer.push_back({nums1[i], nums2[j]});
16+
if (i + 1 < nums1.size() && !visited.contains({i + 1, j})) {
17+
sum_index.push({nums1[i + 1] + nums2[j], {i + 1, j}});
18+
visited.insert({i + 1, j});
19+
}
20+
if (j + 1 < nums2.size() && !visited.contains({i, j + 1})) {
21+
sum_index.push({nums1[i] + nums2[j + 1], {i, j + 1}});
22+
visited.insert({i, j + 1});
23+
}
24+
}
25+
26+
return answer;
27+
}
28+
29+
private:
30+
struct SumIndex {
31+
int sum;
32+
vector<int> index;
33+
34+
bool operator< (const SumIndex& other) const {
35+
return sum > other.sum;
36+
}
37+
};
38+
};

373/step3_1.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
struct不使用パターン
3+
*/
4+
class Solution {
5+
public:
6+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
7+
priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> sum_index;
8+
set<vector<int>> visited;
9+
vector<vector<int>> answer;
10+
sum_index.push({0, 0, 0});
11+
while (answer.size() < k && sum_index.size() > 0) {
12+
int i = sum_index.top()[1];
13+
int j = sum_index.top()[2];
14+
sum_index.pop();
15+
answer.push_back({nums1[i], nums2[j]});
16+
if (i + 1 < nums1.size() && !visited.contains({i + 1, j})) {
17+
sum_index.push({nums1[i + 1] + nums2[j], i + 1, j});
18+
visited.insert({i + 1, j});
19+
}
20+
if (j + 1 < nums2.size() && !visited.contains({i, j + 1})) {
21+
sum_index.push({nums1[i] + nums2[j + 1], i, j + 1});
22+
visited.insert({i, j + 1});
23+
}
24+
}
25+
return answer;
26+
}
27+
};

373/step3_2.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
structを使用したパターン
3+
priority_queueやstructの宣言で若干冗長に感じるが、こちらのほうが読みやすい
4+
*/
5+
class Solution {
6+
public:
7+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
8+
priority_queue<SumIndex, vector<SumIndex>, greater<SumIndex>> sum_index;
9+
set<vector<int>> visited;
10+
vector<vector<int>> minimum_k_pairs;
11+
sum_index.push({nums1[0] + nums2[0], 0, 0});
12+
while (minimum_k_pairs.size() < k && sum_index.size() > 0) {
13+
int i = sum_index.top().num1_index;
14+
int j = sum_index.top().num2_index;
15+
sum_index.pop();
16+
minimum_k_pairs.push_back({nums1[i], nums2[j]});
17+
if (i + 1 < nums1.size() && !visited.contains({i + 1, j})) {
18+
sum_index.push({nums1[i + 1] + nums2[j], i+1, j});
19+
visited.insert({i + 1, j});
20+
}
21+
if (j + 1 < nums2.size() && !visited.contains({i, j + 1})) {
22+
sum_index.push({nums1[i] + nums2[j + 1], i, j + 1});
23+
visited.insert({i, j + 1});
24+
}
25+
}
26+
return minimum_k_pairs;
27+
}
28+
29+
private:
30+
struct SumIndex {
31+
int sum;
32+
int num1_index;
33+
int num2_index;
34+
35+
bool operator> (const SumIndex& other) const {
36+
return sum > other.sum;
37+
}
38+
};
39+
};

373/step3_3.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
{i + 1, j}と{i, j + 1}をpriority_queueにいれる時に、{i + 1, j - 1}と{i - 1, j + 1}がvisitedに含まれているかを確認して効率化するパターン
3+
条件判定部分が無駄に複雑なので関数化したいが、いい感じにできないのでそのままにしている
4+
*/
5+
class Solution {
6+
public:
7+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
8+
priority_queue<SumIndex, vector<SumIndex>, greater<SumIndex>> sum_index;
9+
vector<vector<int>> minimum_k_pair;
10+
set<vector<int>> visited;
11+
sum_index.push({nums1[0] + nums2[0], 0, 0});
12+
while (minimum_k_pair.size() < k && sum_index.size() > 0) {
13+
int i = sum_index.top().num1_index;
14+
int j = sum_index.top().num2_index;
15+
sum_index.pop();
16+
minimum_k_pair.push_back({nums1[i], nums2[j]});
17+
if (i + 1 < nums1.size() && !visited.contains({i + 1, j}) && (j == 0 || visited.contains({i + 1, j - 1}))) {
18+
sum_index.push({nums1[i + 1] + nums2[j], i + 1, j});
19+
visited.insert({i + 1, j});
20+
}
21+
if (j + 1 < nums2.size() && !visited.contains({i, j + 1}) && (i == 0 || visited.contains({i - 1, j + 1}))) {
22+
sum_index.push({nums1[i] + nums2[j + 1], i, j + 1});
23+
visited.insert({i, j + 1});
24+
}
25+
}
26+
return minimum_k_pair;
27+
}
28+
29+
private:
30+
struct SumIndex {
31+
int sum;
32+
int num1_index;
33+
int num2_index;
34+
35+
bool operator> (const SumIndex& other) const {
36+
return sum > other.sum;
37+
}
38+
};
39+
};

373/step3_3_fix.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
{i + 1, j}と{i, j + 1}をpriority_queueにいれる時に、{i + 1, j - 1}と{i - 1, j + 1}がvisitedに含まれているかを確認して効率化するパターン
3+
条件判定部分が無駄に複雑なので関数化したいが、いい感じにできないのでそのままにしている
4+
*/
5+
class Solution {
6+
public:
7+
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
8+
priority_queue<SumIndex, vector<SumIndex>, greater<SumIndex>> sum_index;
9+
vector<vector<int>> minimum_k_pair;
10+
set<vector<int>> visited;
11+
sum_index.push({nums1[0] + nums2[0], 0, 0});
12+
while (minimum_k_pair.size() < k && sum_index.size() > 0) {
13+
int i = sum_index.top().num1_index;
14+
int j = sum_index.top().num2_index;
15+
sum_index.pop();
16+
minimum_k_pair.push_back({nums1[i], nums2[j]});
17+
if (i + 1 < nums1.size() && !visited.contains({i + 1, j}) && (j == 0 || visited.contains({i + 1, j - 1}))) {
18+
sum_index.push({nums1[i + 1] + nums2[j], i + 1, j});
19+
visited.insert({i + 1, j});
20+
}
21+
if (j + 1 < nums2.size() && !visited.contains({i, j + 1}) && (i == 0 || visited.contains({i - 1, j + 1}))) {
22+
sum_index.push({nums1[i] + nums2[j + 1], i, j + 1});
23+
visited.insert({i, j + 1});
24+
}
25+
}
26+
return minimum_k_pair;
27+
}
28+
29+
private:
30+
struct SumIndex {
31+
int sum;
32+
int num1_index;
33+
int num2_index;
34+
35+
bool operator> (const SumIndex& other) const {
36+
return sum > other.sum;
37+
}
38+
};
39+
};

0 commit comments

Comments
 (0)