《算法笔记》学习日记——4.5 二分

4.5 二分

Codeup Contest ID:100000585

问题 A: 找x

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

4
1 2 3 4
3

样例输出

2

思路
这题很简单,之前做到过,是用for循环的方式遍历,这次只要改成用二分查找法就好了。
注意:这题不要用sort函数排序,虽然使用二分查找要保证单调递增或者单调递减,但是这里用了sort函数会改变下标,然后导致答案错误,估计codeup上的OJ本身输入的序列就是有序的,所以不用考虑乱序先排序的问题了。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
int BinarySearch(int a[], int left, int right, int x){
	int mid;
	while(left<=right){
		mid = (left+right)/2;
		if(a[mid]==x) return mid;//找到了x的值,返回x的下标
		else if(a[mid]>x) right = mid-1;
		else left = mid+1; 	
	}
	return -1;//未找到,返回-1 
}
int tmp[201]={0};
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		for(int i=0;i<n;i++) scanf("%d", &tmp[i]);
		int x;
		scanf("%d", &x); 
		printf("%d\n", BinarySearch(tmp, 0, n-1, x));
		memset(tmp, 0, sizeof(tmp));
	}
	return 0;
} 

问题 B: 打印极值点下标

题目描述
在一个整数数组上,对于下标为i的整数,如果它大于所有它相邻的整数,或者小于所有它相邻的整数,则称为该整数为一个极值点,极值点的下标就是i。
输入
每个案例的输入如下:
有2×n+1行输入:第一行是要处理的数组的个数n;
对其余2×n行,第一行是此数组的元素个数k(4<k<80),第二行是k个整数,每两个整数之间用空格分隔。
输出
每个案例输出不多于n行:每行对应于相应数组的所有极值点下标值,下标值之间用空格分隔,如果没有极值点则不输出任何东西。
样例输入

2
4
1 2 1 3
5
3 4 5 6 7

样例输出

0 1 2 3
0 4

思路
这题也是挺简单的,虽然我想不出来怎么用二分的思想去处理……于是乎换了种常规思路来写,就是先把第一个元素和最后一个元素的特殊情况列出来判断,然后再对普遍情况判断,如果满足题设要求,返回true,否则返回false。
这里要注意一下格式问题,首先输出的每行后面不能有空格(这个很普遍,很多题目都有这样的要求),然后是没有极值点就不能输出任何东西(包括换行符),最后是让我一直格式错误50%的地方(应该细心的人不会犯这个错叭hhh):判断第一个极值点的时候要用cnt==1,我一开始写了i==0来判断,这样子的话必须第一个元素是极值点才能正常输出,否则就会开头打一个空格了。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
bool judge(int a[], int n, int x){//传入数组名、数字长度和要查询的下标 
	if(x==0){//先处理第一个和最后一个的情况
		if(a[x]>a[x+1]||a[x]<a[x+1]) return true;
		else return false;
	}
	if(x==n-1){
		if(a[x]>a[x-1]||a[x]<a[x-1]) return true;
		else return false;
	}
	if(a[x]>a[x-1]&&a[x]>a[x+1]) return true;//然后处理普遍情况 
	else if(a[x]<a[x-1]&&a[x]<a[x+1]) return true;
	else return false;
}
int tmp[80]={0};
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		while(n--){
			int k;
			scanf("%d", &k);
			for(int i=0;i<k;i++) scanf("%d", &tmp[i]);
			int cnt = 0; 
			for(int i=0;i<k;i++){
				if(judge(tmp, k, i)){
					cnt++;//有极值点就计数点加1 
					if(cnt==1) printf("%d", i);//如果是第一个极值点,就直接输出 
					else printf(" %d", i);//否则先输出一个空格 
				} 
			}
			if(cnt!=0) printf("\n");//如果有极值点就输出完之后输出一个换行,否则不输出 
			memset(tmp, 0, sizeof(tmp));
		}
	}
	return 0;
} 

问题 C: 查找

题目描述
输入数组长度 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<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
bool BinarySearch(int tmp[], int left, int right, int x){
	int mid;
	while(left<=right){
		mid = (left+right)/2;
		if(tmp[mid]==x) return true;//找到了,返回true
		else if(tmp[mid]>x) right = mid-1;
		else left = mid+1; 
	}
	return false;//没找到,返回false 
} 
int a[101]={0};//存储输入的所有数字 
int b[101]={0};//存储要查找的数字 
int main(){
	int n;
	while(scanf("%d", &n) != EOF){
		for(int i=0;i<n;i++) scanf("%d", &a[i]);
		int m;
		scanf("%d", &m);
		for(int i=0;i<m;i++) scanf("%d", &b[i]);
		sort(a, a+n);//对a数组从小到大排序 
		for(int i=0;i<m;i++){
			if(BinarySearch(a, 0, n-1, b[i])) printf("YES\n");
			else printf("NO\n");
		}
	}
	return 0;
} 

问题 D: 习题5-15 二分法求方程的根

题目不可用!!(黑人问号.jpg)

小结

这部分的题目还是比较简单的,主要都是查找类的问题,或者数学类问题(书上的二分法求根二分法求根号的近似值装水问题木棒切割问题等等)。
对于查找类的题目,如果对数据规模比较小的其实用for循环遍历查找也没太大问题,但是如果数据规模比较大的话就最好用二分查找来做了,只要记得在二分查找之前要先将序列排序就行(单增单减都可以,但是对应的二分查找函数不一样)。
对于数学类的题目,我认为最重要的地方在于从题目中提取信息,找到两个变量之间可能形成的单增或者单减的关系,一旦找到这样的关系之后,接下来用二分法就非常好做了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值