和为给定数(二分法)

题目:


 

描述
给出若干个整数,询问其中是否有一对数的和等于给定的数。

输入
共三行:

第一行是整数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)

优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有最低的优先级。
相同优先级中,按结合顺序计算。大多数运算是从左至右计算,只有三个优先级是从右至左结合的,它们是单目运算符条件运算符赋值运算符
基本的优先级需要记住:
指针最优,单目运算优于双目运算。如正负号。
先乘除(模),后加减。
先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7等价于 (1 << (3 + 2))&7.
逻辑运算最后计算。

果然 我还是又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,那么说明还是可以去判断下,而不是直接循环下一个。

 

posted @ 2024-04-06 13:00  破刀  阅读(61)  评论(1编辑  收藏  举报