批里批里 (゜-゜)つ🍺 干杯|

七つ一旋桜

园龄:4年2个月粉丝:6关注:3

2021-08-26 22:54阅读: 63评论: 0推荐: 0

二分算法笔记

三个模板

基础模板

这个板子是最基础的折半查找,既不偏左也不偏右

int binarySearch(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while(left <= right) {
        int mid = (right + left) / 2;
        if (nums[mid] == target)
            return mid;
        else if (nums[mid] < target)
            left = mid + 1;
        else if (nums[mid] > target)
            right = mid - 1;
    }
    return -1;
}

acwing的算法板子

模板一

当我们将区间[l, r]划分成[l, mid][mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。

int bsearch_1(int l, int r) { // 这个模板实质从左往右找
    while (l < r) {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

模板二

当我们将区间[l, r]划分成[l, mid - 1][mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。

int bsearch_2(int l, int r) { // 这个模板实质从右往左找
    while (l < r) {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

使用板子的时候要注意数据范围,计算mid时可能会爆int,因此推荐默认使用long long来声明mid


洛谷题单

【深基13.例1】查找

模板题

因为要输出的是数字第一次出现的位置且数字可能出现多次,因此使用模板一

check条件为a[mid] <= target,若要找的是数字最后出现的位置,则使用模板二,check条件为a[mid] >= target


A-B 数对

stl里封装了二分相关的函数

lower_bound( begin,end,num,greater<type>())upper_bound( begin,end,num,greater<type>())

lowerbound可以查找小于等于num的最小数的地址,不存在则返回end指针

upper_bound可以查找小于num的最小数的地址,不存在啧返回end指针

思路

原数组排序后,这题对于每个a[i],其可形成数对的数b必定能形成一段连续区间,然后区间长度就是这个数能形成数对的数量,因此可以用二分从后往前找得出的下标减去从前往后找得出的下标的差值+1,也可以使用stl自带的二分函数(其底层和acwing板子有一定差异)

代码实现

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll a[N];
int main() {
  int n, c, ans = 0;
  cin >> n >> c;
  for (int i = 0; i < n; ++i) 
    cin >> a[i];
  sort(a, a + n);
  for (int i = 0; i < n; ++i)
    ans += (upper_bound(a, a + n, a[i] + c) - a) - (lower_bound(a, a + n, a[i] + c) - a);
  cout << ans;
}

当然这两个函数都可以通过上面的基础板子修改得到

upper_bound函数可以用以下代码实现

[&](){
    ll l = i, r = n - 1;
    while (l <= r) {
        ll mid = l + r >> 1;
        if (a[i] + c < a[mid])
            r = mid - 1;
        else
            l = mid + 1;
    }
    return l;
}()

lower_bound函数可以用以下代码实现

[&](){
    ll l = i, r = n - 1;
    while (l <= r) {
        ll mid = l + r >> 1;
        if (a[i] + c <= a[mid])
            r = mid - 1;
        else
            l = mid + 1;
    }
    return l;
}()

这题也可以使用双指针实现

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 10;
int n , c;
int a[N];
int main () {
	cin >> n >> c;
	for(int i = 1 ; i <= n ; i ++) cin >> a[i];
	sort(a + 1 , a + 1 + n);
	int l = 1, r1 = 1 , r2 = 1;
	ll ans = 0;
	for(l = 1 ; l <= n ; l ++) {
		while(r1 <= n && a[r1] - a[l] <= c) r1 ++;
		while(r2 <= n && a[r2] - a[l] < c ) r2 ++;
		ans += r1 - r2;
	}
	cout << ans;
	return 0;
}

其他解法

比较简单的就是用桶来做,把所有a[i]的值用桶存起来,再求出桶中a[i] - c对应的桶的数量即可

因为数据范围可以达到 232 ,因此桶用map实现,或者用数组+离散化

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll a[N];
int main() {
  map<int, int> b;
  int n, c;
  ll ans = 0;
  cin >> n >> c;
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
    b[a[i]]++;
  }
  for (int i = 0; i < n; ++i) {
    if (b.count(a[i] - c))
      ans += b[a[i] - c];
  }
  cout << ans;
}

本文作者:七つ一旋桜

本文链接:https://www.cnblogs.com/poifa/p/15191975.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   七つ一旋桜  阅读(63)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起