算法题目分享(二分算法)

一、跳石头

思路 : 如果我们知道最短的跳跃距离,要求我们算出要移走的石头数量

如果最短的跳跃距离是已知的,我们算出要移走的石头数量,题目规定了最多能移走多少石头,

如果移走石头越多,那么最短的跳跃距离越大(最小跳跃的距离的最大值也许不变,但一定不会小,只会越来越大),所以这里有单调性

最短的跳跃距离我们从0到L之间遍历找(二分的遍历),规定了能移走多少石头<= M :

那么我们可以不断地去试最短的距离(max),也就是求<=M的最右值,就到了二分算法的领域

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5;
int a[N];
int l,n,m;
int check(int mid)//mid是最小的跳越距离,check()得到所需的去掉的石头
{
  int i=0,j=1,count=0;
  while(j<=n+1)
  {
    if(a[j]-a[i]>=mid)
    i=j;
    else//a[j]-a[i]<mid
    count++;
    j++;
  }
  return count;
}

int main()
{
  // 请在此输入您的代码
  cin>>l>>n>>m;
  for(int i=1;i<n+1;i++)
  cin>>a[i];
  a[n+1]=l;
  int left=0,right=l;
  while(left<right)
  {
    int mid=left+(right-left+1)/2;
    if(check(mid)<=m)
    left=mid;
    else//>m
    right=mid-1;
  }
  cout<<left;
  return 0;
}
二、肖恩的苹果林

  • 思路一

N个坑要种M棵树,那么还剩下N-M个坑,把N-M个坑看作是上一道题中的要搬走的石头,这里就是要填的坑,我们看到最大的最近距离就要想到用二分,在[0,1e9] 中不断地去试最近距离是多少,当最近距离是mid时,要移走多少个坑,这就与上面的题目的思路是一样的,上面题目是至多移走m块石头,而这里是最多移走N-M块坑,为什么是最多,因为可能移走2块坑和移走3块坑的最小距离是一样的,所以最多不能超过N-M块坑,(不能限定死是N-M个坑,因为有可能结果不需要移走哦N-M个坑) 所以只需要把上面的题目中的<=m,换成<=(N-M)(target) 即可

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N];
int n,m;
int check(int mid)//mid是两棵苹果树之间的最近距离,check()得到所需的去掉的坑
{
  int i=1,j=2,count=0;
  while(j<n+1)
  {
    if(a[j]-a[i]>=mid)
    i=j;
    else//a[j]-a[i]<mid
    count++;
    j++;
  }
  return count;
}

int main()
{
  cin>>n>>m;
  for(int i=1;i<n+1;i++)
  cin>>a[i];
  sort(a+1,a+n+1);

  int target=n-m;//要移走的坑的数量
  int left=0,right=1e8,mid=0;//left和right去逼近最大的最近距离,最大的最近距离=[1,9]
  while(left<right)
  {
    int mid=left+(right-left+1)/2;
    if(check(mid)<=target)
    left=mid;
    else//>m
    right=mid-1;
  }
  cout<<left;
  return 0;
}

check函数要变,要从第一个树往后check

另一种写法 :

cpp 复制代码
int main()
{
    cin>>n>>m;
    for(int i=1;i<n+1;i++)
    cin>>a[i];
    sort(a+1,a+n+1);
    int t=n-m;
    int l=0,r=1e9+1;
    while(l+1!=r)
    {
        int mid=l+(r-l)/2;
        if(check(mid)<=t)
        l=mid;
        else
        r=mid;
    }
    cout<<l<<endl;
    return 0;
}
  • 思路二

依旧是用二分去逼近最小距离,我们可以看当最小距离是mid时,我们能种多少棵树,mid越大,能种的树越少,能种的树要>=N,所以

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int a[N];
int n,m;
int check(int mid)//看最小距离是mid时,能种多少棵树
{
  int i=1,j=2,count=1;//count是指第一棵树,已经包含进来了
  while(j<n+1)
  {
    if(a[j]-a[i]>=mid)
    {
      count++;
      i=j;
    }
    j++;
  }
  return count;
}

int main()
{
  cin>>n>>m;
  for(int i=1;i<n+1;i++)
  cin>>a[i];
  sort(a+1,a+n+1);

  int left=0,right=1e8,mid=0;//left和right去逼近最大的最近距离,最大的最近距离=[0,1e8]
  while(left<right)
  {
    int mid=left+(right-left+1)/2;
    if(check(mid)>=m)
    left=mid;
    else//>m
    right=mid-1;
  }
  cout<<left;
  return 0;
}

另一种二分写法:

cpp 复制代码
  int left=0,right=1e8,mid=0;//left和right去逼近最大的最近距离,最大的最近距离=[0,1e8]
  while(left+1!=right)//当left与right相邻时退出
  {
    int mid=(left+right)>>1;
    if(check(mid)>=m)//能种>=m棵树
    right=mid;//right缩小
    else
    left=mid;
  }
三、区间或

这道题关键是用前缀和思想去做,求a[2] 到 a[3] 之间的 |的结果,那a[1] | a[2] | a[3] 的结果要去除掉 | a[1]的效果,这该怎么搞,,我们可以看a[1] 对结果的贡献, | 是那一位比特位是1,结果的是比特位上就是1,所以我们可以看每一个数字的每一位比特位上是1还是0 ,对每个数字的一个比特位做前缀和,(在检查时只需要看一个比特位上是否大于0 即可),用一个二维数组[32][N] ,前面代表每一个比特位,后面的每一位代表前缀和,这样我们想去掉 | a[1] 的效果就减去a[1] 在每个比特位上的数(1/0),反正减去后如果该比特位上的数依旧大于0, 说明有其他数字在该位上是1 的 ,结果不影响

二维数组 :

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],d[36][N];
int main()
{
  int n,q;cin>>n>>q;
  for(int i=1;i<=n;i++)
  cin>>a[i];
  for(int i=0;i<=30;i++)
  {
    for(int j=1;j<=n;j++)
    {
      d[i][j]=d[i][j-1]+((a[j]>>i)&1);
    }
  }

  for(int i=0;i<q;i++)//q次查询
  {
    int x,y,num=0;cin>>x>>y;//要减去a[1]的32个比特位上的数字哦
    for(int j=0;j<=30;j++)
    {
      if(d[j][y]-d[j][x-1])//这一位上是"1"的
      {
        num|=(1<<j);
      }
    }
    cout<<num<<endl;
  }
  return 0;
}
相关推荐
隔壁大炮2 小时前
10.PyTorch_元素类型转换
人工智能·pytorch·深度学习·算法
玛丽莲茼蒿2 小时前
Leetcode hot100 矩阵置零【中等】
算法·leetcode·矩阵
澈2072 小时前
算法进阶:二叉树翻转与环形链表解析
数据结构·算法·排序算法
:1212 小时前
java数组2
java·算法·排序算法
代码飞天2 小时前
算法与数据结构之树——让数据查找更加迅速
数据结构·算法
贾斯汀玛尔斯2 小时前
每天学一个算法--外部排序(External Sorting)
算法
故事和你912 小时前
洛谷-算法2-2-常见优化技巧1
开发语言·数据结构·c++·算法·动态规划·图论
酉鬼女又兒2 小时前
JavaLeetCode 第一题「两数之和」:从暴力枚举到一遍哈希表的正确与错误实现,详解HashMap核心知识点及常见陷阱
java·开发语言·数据结构·算法·leetcode·职场和发展·散列表
黎阳之光2 小时前
视频孪生重构轨交数字孪生新范式|黎阳之光以自主核心技术破解落地难题
大数据·人工智能·算法·安全·数字孪生