和为给定数(二分法)
题目:
描述
给出若干个整数,询问其中是否有一对数的和等于给定的数。
输入
共三行:
第一行是整数n(0 < n <= 100,000),表示有n个整数。
第二行是n个整数。整数的范围是在0到10^8之间。
第三行是一个整数m(0 <= m <= 2^30),表示需要得到的和。
输出
若存在和为m的数对,输出两个整数,小的在前,大的在后,中间用单个空格隔开。若有多个数对满足条件,选择数对中较小的数更小的。若找不到符合要求的数对,输出一行No。
样例输入
4
2 5 1 4
6
样例输出
1 5
解题思路
定义一个标志,默认值为0
把数组按从小到大排序
写一个for循环对数组的每一项进行遍历,在for循环中利用二分查找查找在剩余的每一项中是否有和为给定的数,如果有给标志赋值1,并跳出循环
for循环结束后如果标志值仍然为0,则输出No
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 5 int f = 0; //标志数 6 7 int main() 8 { 9 int n,m; 10 cin >> n; 11 int num[n]; 12 for(int i = 0; i < n; i++){ 13 cin >> num[i]; 14 } 15 cin >> m; 16 17 sort(num, num + n); //对数组进行升序排序 18 19 for(int i = 0; i < n; i++){ 20 int left = i + 1, right = n; 21 while(left < right){ 22 int mid = (left + right) / 2; 23 //找到给定值输出结果并结束循环 24 if(num[mid] + num[i] == m){ 25 f = 1; 26 cout << num[i] << " " << num[mid] << endl; 27 break; 28 } 29 if(num[i] + num[mid] < m){ 30 left = mid + 1; 31 } 32 else{ 33 right = mid - 1; 34 } 35 } 36 if(f == 1) break; //如果标志为1代表已经输出了需要的结果,无需后续遍历 37 } 38 39 //未找到给定数 40 if(f == 0){ 41 cout << "No" << endl; 42 } 43 44 return 0; 45 }
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/m0_51684823/article/details/129189796
-------------------------------------------------
中间的坑
用血与泪的经历告诉你们这道题的思路orz
1、开始 我是这样想的 从那些数中 找出一个比给定数小一位的数,然后找m-比他小一位的数是否在序列中,但是还要判断比他小一位的数
是否在序列中等诸多问题(orz),然后就wrong了
后来 题解 的方法是将序列按升序排序,从第一位开始,看看m-第一位是否在序列中。。正好与我相反(orz)
然后又wrong了QAQ
2、有个坑 如果 2个数 1 3 给定数为2,那么就会输出1 1,这是不对的,1重复使用了。所以还要判断重复使用。在二分查找的时候,函数的返回值是他的位置
并且找到的这个位置不能等于他正在枚举的数的位置,这样就避免了、、、、
但是 又 wrong了
3、原来 是 移位运算的顺序0-0
l+(r-l)/2 这是我的本意 然后我用了移位运算 l+(r-l)>>1,这样是不对的
因为 (下面贴一大段qwq)
果然 我还是又wrong了。。。
4、原来我开始定义的long long 格式化却用的%d。。。。
还有一种做法:
函数介绍
lower_bound()返回一个iterator(迭代器)它指向在 [first,last)标记的 有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个大于等于value。 其实还有upper_bound();upper_bound()返回的是最后一个大于等于val的位置。
注意事项
调用lower_bound之前必须确定序列为有序序列,否则调用出错。第一个版本排序根据底层的 <(小于)操作符,第二个版本根据comp进行排序。
函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,是查找序列中的第一个出现的值大于等于val的位置;
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/nyist_tc_lyq/article/details/50973488
第14行,if(b-a==i && *(b+1)!=*b) contimue;
b-a==i 是判断查找的这个值,是不是找到了自己。
*(b+1)!=*b 是判断自己身后(序号高的后面)是否有一个和自己一样的数。
如果找到了自己,且自己身后还有一个和自己一样的数。那就满足要求。
类似于
7
1 5 3 3 1 4 8
6
你i指向“3”这个数,且你要找6-3 的时候。
你会找到自己,如果 *(b+1) == *b,那么说明还是可以去判断下,而不是直接循环下一个。