基础算法-3.2

本文详细介绍了贪心算法中的双指针策略(对撞指针和快慢指针),以及它们在整数和浮点二分查找中的应用。通过实例演示了如何结合检查函数进行问题求解,特别关注于二分法在求解特定问题中的关键作用。
摘要由CSDN通过智能技术生成

贪心

例题

2)

双指针

双指针通常用于在数组或字符串中进行快速查找、匹配、排序或移动操作。

双指针并非真的使用指针实现,一般用两个变量来表示下标(在后面都用指针来表示)。

常见的指针模型:1)对撞指针  2)快慢指针

对撞指针

指的是两个指针left, right(简写 l  ,  r),分别指向序列的第一个元素和最后一个元素。

然后在满足一定条件后不断递减或递增。

直到左右指针相撞( l==r)。

例题:

快慢指针

指的是两个指针从同一侧开始遍历序列,且移动的歩长一个快一个慢。

步骤:

使用两个指针 l,r  ,l 指向序列的第一个元素,r一般指向序列的第零个元素,都像右边移动,直至l==n且r==n,或两指针相交跳出循环。

例题:

二分

整数二分

就是在一个已有的有序数组上进行二分查找,一般为找出某个值的位置,或者是找出分界点。数组大小一般在1e6以内。


//整数二分模板

int l = 0, r = 1e9;
while (l + 1 != r)
{
	int mid = (l + r) / 2;

	if (a[mid] >= x) r = mid;
	else l = mid;
}
cout << r << '\n';

例题

浮点二分

不在是在有序数组上二分查找,而是在某个实数范围内进行查找。实数域本身也是单调的。

区别:使用的变量类型,退出的判断条件。(不太重要)


//浮点二分模板
double l = 0, r = 1e9, esp = 1e-6;
//这样的判断条件可保证l r最终可以收敛到分界点
while (r - 1 >= esp) // esp是一个极小值,设置为1e-6较为合适
{
	double mid = (l + r) / 2;
	//f(x)单调增,f(x)>=0,说明mid偏大。
	if (f(mid) >= 0) r = mid;
	else l = mid;
}
cout << r << '\n'; //返回l,r,差别不大

二分答案

二分法最常见最重要的题型。

模型:二分框架+check函数

我们会将答案进行二分 ,然后枚举可能解后判断是否可以更优或是否合法,不断逼近最优解。

特征:已知某个答案,容易判断是否合法或更优。


//二分答案
bool check(int mid)
{
	bool res = true;
	return res;//判断中点的合法性
}
int main()
{
	int l = 0, r = 1e9;
	while (l + 1 != r)
	{
		int mid = (l + r) / 2;
		if (check(mid))  l = mid;
		else r = mid;
	}
	cout << l << '\n';
	return 0;
}

例题:

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5e4+9;
int a[N],L,n,m;

int check(int mid)
{
  int res=0,lst=0;
  for(int i=1;i<=n;++i) 
  {
    if(a[i]-a[lst]<mid)//lst 上一个数
    {
      res++;
      continue;
    }
    lst =i;
  }
  if(L-a[lst]<mid) return m +1;//表示不允许
  return res;
}


int  main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  cin>> L>>n>>m; //距离,岩石数,至多移走的岩石数
  for(int i=1;i<=n;++i) cin>> a[i];
  ll l=0,r=1e9+5;
  while(l+1!=r) 
  {
    ll mid=(l+r)/2;
    if(check(mid)<=m)  l=mid;
    else r=mid;
  }
  cout << l << '\n';
  return 0;
}

例题:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int x[N];
int n,m;

int check(int mid)
{
  int res=0;
  for(int i=1,lst =0;i<=n;++i) 
  {
    if(lst && x[i]-x[lst]<mid)  continue;
    res++,lst=i;

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

  int l=0,r=1e9+5;
  while(l+1!=r)
  {
    int mid =(l+r)>>1;
    if(check(mid)>=m)  l=mid;
    else r=mid;
  }
  cout << l << '\n';
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值