ALGO[1]
雙指針&二分搜&分治
INDEX
Two Pointer
Binary Search
Divide & Conquer
Two Pointers
雙指針
1. 正反指針
2. 快慢指針
Two Pointers
雙指針
就是兩根指針
(啊說是指針但他不是指標)
有正反指針、快慢指針、指向不同陣列的指針......
正反指針
快慢指針
Two Pointers
例子
Sum of Two Values
給你 個正整數,找到兩個不同位置的數字相加為 的索引
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (arr[i] + arr[j] == x) {
cout << i << ' ' << j << '\n';
return 0;
}
}
}
如果這樣寫
複雜度
會 TLE
怎麼在
內解決?
Two Pointers
Solution
使用雙指針
Two Pointers
AC Code
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int n, x;
cin >> n >> x;
vector<pair<int, int>> v(n); // first for number, second for index
for (int i = 0; i < n; i++) {
cin >> v[i].first;
v[i].second = i + 1;
}
sort(begin(v), end(v));
int l = 0, r = n - 1;
while (l < r) {
if (v[l].first + v[r].first == x) {
cout << v[l].second << ' ' << v[r].second << '\n';
return 0;
} else if (v[l].first + v[r].first > x) {
r--;
} else l++;
}
cout << "IMPOSSIBLE\n";
}
Two Pointers
例子
Subarray Sums I
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
for (int k = i; k <= j; k++) {
sum += arr[k];
}
if (sum == x) ans++;
}
}
Two Pointers
Solution
用兩個快慢不同的指針
Two Pointers
AC Code
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, x;
cin >> n >> x;
vector<int> v(n);
for (int i = 0; i < n; i++) {
cin >> v[i];
}
int ans = 0;
int r = 1, sum = v[0];
for (int l = 0; l < n; l++) {
while (sum < x && r < n) {
sum += v[r];
r++;
}
if (sum == x) ans++;
sum -= v[l];
}
if (sum == x) ans++;
cout << ans << '\n';
}
Two Pointers
題單
Binary Search
二分搜
1. 單調性
2. 對答案二分搜
Binary Search
找數字
for (int i = 0; i < n; i++) {
if (arr[i] == x) {
// x found at index i
}
}
Binary Search
找數字
二分搜
Binary Search
找數字
Binary Search
判斷
實作
Binary Search
實作
int l = 0, r = n - 1;
while (l < r) {
int mid = (l + r) / 2;
if (mid >= x) {
r = mid;
} else {
l = mid + 1;
}
} // 最後 l == r == x
int l = 0, r = n;
while (l + 1 < r) {
int mid = (l + r) / 2;
if (mid >= x) {
r = mid;
} else {
l = mid;
}
} // 最後 l == r - 1 == x
Binary Search
實作
upper_bound:返回陣列中第一個大於 的值的指標
lower_bound:返回陣列中第一個大於等於 的值的指標
auto k = lower_bound(arr, arr + n, x) - arr;
if (k < n && arr[k] == x) {
// x found at index k
}
啊記得陣列要先排序過
set<int> s;
auto it = s.lower_bound(x);
if (it != s.end() && *it == x) {
// x found in set
}
Binary Search
例子
for (int time = 1; time <= sum * t; time++) {
int prod = 0;
for (int i = 0; i < n; i++) {
prod += time / k[i];
}
if (prod >= t) {
cout << time << '\n';
break;
}
}
Binary Search
Solution
對答案二分搜
Binary Search
AC Code
#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
int main() {
int n, t;
cin >> n >> t;
vector<int> k(n);
for (int i = 0; i < n; i++) {
cin >> k[i];
}
ll l = 1, r = 1e18;
while(l < r) {
ll mid = (l + r) / 2, sum = 0;
for (int i : k) {
sum += mid / i;
if (sum > t) break;
}
if(sum >= t) r = mid;
else l = mid + 1;
}
cout << l << '\n';
}
Binary Search
例子
Binary Search
AC Code
#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
ll MAX_NUM = 2e5 * 1e9;
int n, k;
vector<int> arr;
bool check(ll max_num) {
int subarr_count = 0;
ll cur_sum = 0;
for (int x : arr) {
if (x > max_num) return false;
if (cur_sum + x > max_num) {
subarr_count++;
cur_sum = 0;
}
cur_sum += x;
}
if (cur_sum > 0) subarr_count++;
return subarr_count <= k;
}
int main() {
cin >> n >> k;
arr.resize(n);
for (int &i : arr) cin >> i;
ll l = 1, r = MAX_NUM;
while (l < r) {
ll mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << l << '\n';
}
Binary Search
題單
Divide & Conquer
分治,分而治之
1. Merge Sort
2. Binary Exponentiation
3. Minimum Euclidean Distance
Divide and Conquer
Merge Sort
下列兩個已排序陣列按照順序合併的時間複雜度是多少?
然後你會 Merge Sort 了
Divide and Conquer
Merge Sort
Divide and Conquer
Code
#include <iostream>
#include <vector>
using namespace std;
// [l, r]
void mergeSort(vector<int> &arr, int l, int r) {
if (l == r) return;
int m = (l + r) / 2;
mergeSort(arr, l, m), mergeSort(arr, m + 1, r);
int n1 = m - l + 1, n2 = r - m;
vector<int> L(n1), R(n2);
for (int i = 0; i < n1; i++) {
L[i] = arr[l + i];
}
for (int i = 0; i < n2; i++) {
R[i] = arr[m + 1 + i];
}
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}
int main() {
int n = 5;
vector<int> arr = {4, 8, 7, 6, 3};
mergeSort(arr, 0, n - 1);
for (int a : arr) cout << a << ' ';
}
Divide and Conquer
例子
Exponentiation
Divide and Conquer
AC Code
#include <iostream>
using namespace std;
using ll = long long;
const int mod = 1e9 + 7;
// 遞迴式
ll power(ll x, int y) {
if (y == 0) return 1;
if (y == 1) return x;
ll temp = power(x, y / 2);
if (y % 2) return temp * temp * x % mod;
else return temp * temp % mod;
}
// 迭代式
ll binpow(ll x, int y) {
ll ret = 1;
while (y) {
if (y & 1) ret = ret * x % mod;
x = x * x % mod;
y >>= 1;
}
return ret;
}
int main() {
int n;
cin >> n;
while (n--) {
int a, b;
cin >> a >> b;
cout << binpow(a, b) << '\n';
}
}
Binary Search
題單
Bonus
掰掰
雙指針&二分搜&分治
By keaucucal
雙指針&二分搜&分治
- 306