owned this note
owned this note
Published
Linked with GitHub
# Leetcode刷題學習筆記 -- Two-Pointers Binary Search
## Introduction
問題: 在一個vector<int>中,找出兩個element的和為target。
最直覺的解法是暴力破解。
```cpp=
vector<int> nums{1, 3, 5, 2, 4, 6};
int target = 6;
int ans = 0;
for(int i = 0; i < nums.size(); ++i) {
for(int j = i + 1; j < nums.size(); ++j) {
if(nums[i] + nums[j] == target)
return {i, j};
}
}
```
其中 time complexity : $O(N^2)$,效果不是很好。
仔細觀察所有2 sum的組合為
```cpp
{1, 3, 5, 2, 4, 6} --sort--> {1, 2, 3, 4, 5, 6}
{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}
{2, 3}, {2, 4}, {2, 5}, {2, 6}
{3, 4}, {3, 5}, {3, 6}
{4, 5}, {4, 6}
{5, 6}
{3, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11}
```
當我們對vector<int> nums排序後,我們就可以從結果的中間值開始搜尋,從上面的例子來看就是7。
```cpp
{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6} <-{i, j}
{2, 3}, {2, 4}, {2, 5}, {2, 6}
{3, 4}, {3, 5}, {3, 6}
{4, 5}, {4, 6}
{5, 6}
{3, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11}
/|\
|
```
我們從中間值開始找,如果要找的值比target還大,那就移動i往上尋找,如果比target還小那就移動j往下尋找。
ex:移動i往大的值尋找
```cpp
{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}
{2, 3}, {2, 4}, {2, 5}, {2, 6} <-{i, j}
{3, 4}, {3, 5}, {3, 6}
{4, 5}, {4, 6}
{5, 6}
{3, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11}
/|\
|
```
ex:移動j往小的值尋找
```cpp
{1, 2}, {1, 3}, {1, 4}, {1, 5},<-{i, j} {1, 6}
{2, 3}, {2, 4}, {2, 5}, {2, 6}
{3, 4}, {3, 5}, {3, 6}
{4, 5}, {4, 6}
{5, 6}
{3, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11}
/|\
|
```
所以程式碼可以如下
```cpp=
vector<int> nums{1, 3, 5, 2, 4, 6};
sort(nums.begin(), nums.end());
int i = 0, j = nums.size() - 1;
while(i < j) {
if(nums[i] + nums[j] > target) --j;
else if(nums[i] + nums[j] < target) ++i;
else { // 找到一組這樣的組合
rtn.push_back({nums[i], nums[j]});
i++; // 往左斜下尋找
j--;
}
}
return {-1, -1}; // 找不到這樣的組合
```
或是使用下面的方法
```cpp=
for(int i = 0, j = nums.size() - 1; i < j; ++i) {
while(i < j && nums[i] + nums[j] >= target){
if(nums[i] == nums[j] == target)
rtn.push_back({nums[i], nums[j]});
--j;
}
}
```
另一種題目的問法是,找出小於等於target的組合數。
這時候可以用以下的方法。
```cpp=
for(int i = 0, j = nums.size() - 1; i < j; ++i) {
while(i < j && nums[i] + nums[j] > target)
--j;
ans += j - i;
}
```
## Problems
### [2563. Count the Number of Fair Pairs](https://leetcode.com/problems/count-the-number-of-fair-pairs/description/)
找出滿足
1. 0<=i<j<nums.size(),
2. lower <= nums[i] + nums[j] <= upper
所以有的組合數。
```cpp=
class Solution {
long long countLess(vector<int>& nums, int target) {
long long ans{0};
for(int i = 0, j = nums.size() - 1; i < j; ++i) {
while(i < j && nums[i] + nums[j] > target) --j;
ans += j - i;
}
return ans;
}
public:
long long countFairPairs(vector<int>& nums, int lower, int upper) {
sort(nums.begin(), nums.end());
return countLess(nums, upper) - countLess(nums, lower - 1);
}
};
```
###### tags: `leetcode` `刷題`