【数据结构与算法】学习笔记-《算法笔记》-12【二分】

按顺序查找的方法,时间复杂度为O[n];
二分法的时间复杂度为O[logn]。

示例:
在A[n]={1,3,4,6,7,8,10,11,12,15}中找到6和9的下标(失败返回-1)

#include "stdafx.h"
#include <cstdio>

int binaryS(int A[], int left, int right, int x)
{
	int mid;
	while (left <= right)
	{
		mid = (left + right) / 2;
		if (A[mid] < x)
			left = mid + 1;
		if (A[mid] > x)
			right = mid - 1;
		if (A[mid] == x)
			return mid;
	}
	return -1;
}

int main()
{
	int A[10] = { 1,3,4,6,7,8,10,11,12,15 };
	binaryS(A, 0, 9, 9);
	printf("%d\n%d\n", binaryS(A, 0, 9, 6), binaryS(A, 0, 9, 9));
	return 0;
}

更进一步的问题: 如果递增序列A中的元素可能重复,那么如何对给定的欲查询元素x,求出序列中第一个大于等于x的元素的位置L以及第一个大于x的元素的位置R,这样元素x在序列中的存在区间就是左闭右开区间。

子问题1:

//A[]为递增序列,x为欲查询的数,函数返回第一个大于等于x的元素的位置
//二分上下界为左闭右闭的[left,right],传入的初值为[0,n]
int lower_bound(int A[], int left, int right, int x)
{
	int mid;
	while (left < right)//left==right意味着找到唯一位置
	{
		mid = (left + right) / 2;
		if (A[mid] < x)
		{
			left = mid + 1;
		}
		else
		{
			right = mid;
		}
	}
	return left;//返回夹出来的位置
}

子问题2:

int upper_bound(int A[], int left, int right, int x)
{
	int mid;
	while (left < right)//left==right意味着找到唯一位置
	{
		mid = (left + right) / 2;
		if (A[mid] > x)
		{
			right = mid;
		}
		else
		{
			left = mid + 1;
		}
	}
	return left;//返回夹出来的位置
} 
		

以上两个子问题的区别仅仅在于A[mid]>=0和A[mid]>0(即需要满足的条件)
解决“寻找有序序列第一个满足某条件的元素的位置”问题的固定模板

二分区间是左开右闭区间,循环条件应该是left+1<right,退出循环时有left+1=right成立,使得(left,right]才是唯一位置。而由于变成了左开,left的初值比解的最小取值小1,例如对下标从0开始的序列来说,left和right的取值应该是-1和n返回right

二分法求开方

#include <cstdio>
#include <algorithm>
using namespace std;
double eps = 10e-5;

double f(double x)
{
	return x * x;
}

double calSqrt(double a, double b, double out)
{
	double left = a, right = b, mid;
	while (right - left > eps)						//控制精度
	{
		mid = (left + right) / 2;
		if (f(mid) < out)
			left = mid;
		else
			right = mid;
	}
	return mid;
}

装水问题
在这里插入图片描述
f()/calh()是我写的,f0()/solve()是书上的示例

#include <cstdio>
#include<math.h>
#include <algorithm>
using namespace std;
const double eps = 10e-5;
const double Pi = acos(-1.00);

double f(double R, double h)
{
	double L = sqrt(R*R - (R - h)*(R - h));
	double alpha = asin(L / R);
	//double alpha = r * pi;
	return (alpha * R*R / 2 - (R - h)*L / 2)*2;//Sr
}

double calh(double R, double r)
{
	double SR = R * R*Pi / 2, Sr;
	double left = 0, right = R, mid;
	double want = SR * r;
	while (right - left > eps)						//控制精度
	{
		mid = (left + right) / 2;
		if (f(R, mid) < want)
			left = mid;
		else
			right = mid;
	}
	return mid;
}

double f0(double R, double h)
{
	double alpha = 2 * acos((R - h) / R);
	double L = 2 * sqrt(R*R - (R - h)*(R - h));
	double S1 = alpha * R*R / 2 - L * (R - h) / 2;
	double S2 = Pi * R*R / 2;
	return S1 / S2;
}

double solve(double R, double r)
{
	double left = 0, right = R, mid;
	while (right - left > eps)
	{
		mid = (left + right) / 2;
		if (f0(R, mid) > r)
		{
			right = mid;
		}
		else {
			left = mid;
		}
	}
	return mid;
}
int main()
{
	double R, r;
	scanf("%lf%lf", &R, &r);
	printf("%lf\n%lf", calh(R,r),solve(R,r));
	return 0;
}

对于运算式ab %m,用for循环做

for(int i = 0; i < b; i++)
{
	ans = ans * a % m;
}

它的时间复杂度是O(b);
用二分幂(快速幂)的思想,它的时间复杂度是O(logb)
递归写法

typedef long long LL;

//求a^b%m 递归写法
LL binaryPow(LL a, LL b, LL m)
{
	if (b == 0)	return 1;
	if (b % 2 == 0)
	{
		LL temp = binaryPow(a, b / 2, m);
		return temp * temp % m;
	}
	/*if (b % 2 != 0)*/
	else
	{
		LL temp = binaryPow(a, b - 1, m);
		return temp * a%m;
	}
}


int main()
{
	double R, r;
	scanf("%lf%lf", &R, &r);
	printf("%lf\n%lf", calh(R,r),solve(R,r));
	return 0;
}

在上面的代码中,条件if(b%2= =1)可以用if(b&1)代替,因为b&1进行位与操作,判断b的末位是否为1,因此当b为奇数时返回1。这种方式可以提高执行速度。
还要注意当b%2=0时不要直接返回binaryPow(a,b/2%m) * binaryPow(a,b/2%m),会导致复杂度加剧。
细节问题:

  • 如果初始时a有可能大于等于m,那么进入函数前就让a对m取模
  • 如果m为1,可以直接在函数外部判为0;

迭代写法
在这里插入图片描述

typedef long long LL;

//快速幂的迭代写法
LL binaryPow(LL a, LL b, LL m)
{
	LL  temp = 1;
	while(b>0)
	{
		temp *= a * (b & 1) % m;
	/*	if (b & 1)
		{
			temp = a*temp % m;
		}*/
		b /= 2;
		a = a * a%m;
	}
	return temp;
}

习题

找x

题目描述
输入一个数n,然后输入n个数值各不相同,再输入一个值x,输出这个值在这个数组中的下标(从0开始,若不在数组中则输出-1)。
输入
测试数据有多组,输入n(1<=n<=200),接着输入n个数,然后输入x。
输出
对于每组输入,请输出结果。
样例输入
4
1 2 3 4
3
样例输出
2

#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;


struct nu {
	int id;
	int num;
}a[210];

bool cmp(nu a, nu b)
{
	return a.num < b.num;
}

//找X
int main()
{
	int n;
	int x;
	int mid;
	int L, R;
	while (scanf("%d", &n) != EOF)
	{
		for (int i = 0; i < n; i++)
		{
			a[i].id = i;
			scanf("%d", &a[i].num);
		}
		scanf("%d", &x);
		sort(a, a + n, cmp);
		int left = 0, right = n;
		while (left<right)
		{
			mid = (left + right) / 2;
			if (a[mid].num >=x)
				right = mid;
			if(a[mid].num<x)
				left = mid+1;				
		}
		if (a[left].num == x)
		{
			L = left;
			//left = 0;
			//right = n;
			//while (left < right)
			//{
			//	mid = (left + right) / 2;
			//	if (a[mid].num > x)
			//	{
			//		right = mid;
			//	}
			//	else
			//	{
			//		left = mid + 1;
			//	}
			//}
			//R = left-1;
		//	for (int j = L; j <= R; j++)
		//	{
		//		printf("%d", a[j].id);
		//		if (j != R)
		//			printf(" ");
		//	}
		//	printf("\n");
			printf("%d\n", a[L].id);
		}
		else
			printf("-1\n");
	}
	return 0;
}

还不知道这题做错在哪里

查找

题目描述
输入数组长度 n
输入数组 a[1…n]
输入查找个数m
输入查找数字b[1…m]
输出 YES or NO 查找有则YES 否则NO 。
输入
输入有多组数据。
每组输入n,然后输入n个整数,再输入m,然后再输入m个整数(1<=m<=n<=100)。
输出
如果在n个数组中输出YES否则输出NO。
样例输入
6
3 2 5 4 7 8
2
3 6
样例输出
YES
NO

#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;

void func(int a[],int b,int n)
{
	int left = 0, right = n-1;
	int mid;
	bool flag = false;
	while (left <= right)
	{
		mid = (left + right) / 2;
		if (b > a[mid])
			left = mid + 1;
		if(b< a[mid])
			right = mid - 1;
		if (b == a[mid])
		{
			flag = true;
			printf("YES\n");
			break;
		}
	}
	if (flag==false)
		printf("NO\n");
	return;
}

int main()
{
	int m, n;
	int forwardleft = 0;
	int a[110], b[110];
	while (scanf("%d", &n) != EOF)
	{
		for (int q = 0; q < n; q++)
			scanf("%d", &a[q]);
		sort(a, a + n);
		scanf("%d", &m);
		for (int q = 0; q < m; q++)
		{
			scanf("%d", &b[q]);
		}
		for (int q = 0; q < m; q++)
		{
			 func(a, b[q], n);
		}
	}
}
发布了43 篇原创文章 · 获赞 4 · 访问量 1212

猜你喜欢

转载自blog.csdn.net/weixin_42176221/article/details/101514928