题目描述:
给出N个整数,你来判断一下是否能够选出4个数,他们的和为0,可以则输出”Yes”,否则输出”No”。
Input
第1行,1个数N,N为数组的长度(4 <= N <= 1000)
第2 - N + 1行:Aii(-10^9 <= Aii <= 10^9)
Output
如果可以选出4个数,使得他们的和为0,则输出”Yes”,否则输出”No”。
Sample Input
5
-1
1
-5
2
4
Sample Output
Yes
解题报告:
- 折半枚举的思路
- 要求a+b+c+d = 0 ,那么转化为 c+d = -a - b
- 如果随机枚举,去除重复比较烦,不太好弄,那么可以先给原数组排序
- 排序后可以使用定序的技巧,可以比较下面俩个代码,自己输出体会一下
代码一:
for(int i = 0;i < n;i++)
{
for(int j = 0;j < n;j++)
{
for(int k = 0;k < n;k++)
{
for(int l = 0;l < n;l++)
{
printf("%d %d %d %d = %d\n",i,j,k,l,a[i] + a[j] + a[k] + a[l]);
}
}
}
}
代码二:
for(int i = 0;i < n;i++)
{
for(int j = i+1;j < n;j++)
{
for(int k = j+1;k < n;k++)
{
for(int l = k+1;l < n;l++)
{
printf("%d %d %d %d = %d\n",i,j,k,l,a[i] + a[j] + a[k] + a[l]);
}
}
}
}
- 四重循环会超时,折半枚举加双向搜索
- 直接上代码:
-
# include <cstdio>
# include <algorithm>
using namespace std;
const int maxn = 1005;
int main()
{
int n;
long long a[maxn];
scanf("%d",&n);
for(int i = 0;i < n;i++)
{
scanf("%lld",&a[i]);
}
sort(a,a+n); //将原数组排序
for(int i = 0;i < n;i++) //枚举第一个数
{
for(int j = i+1;j < n;j++) //枚举第二个数
{
long long res = -a[i] - a[j]; //前俩个数的和的相反值等于后俩个数的和
int l = j+1,r = n-1; //l枚举第三个数,r枚举第四个数
while(l<r)
if(res == (a[l] + a[r]))
{
printf("Yes\n");
return 0;
}
else if(res > (a[l] + a[r])) //如果大于,说明后俩个数和较小,
{ //那么l++,因为数组已经排序,l+1肯定大于l
l++;
}
else if(res < (a[l] + a[r])) //同理小于的话,说明后俩个数和太大,就减小r的值
{
r--;
}
}
}
printf("No\n");
return 0;
}
- 上面的源码就是将内层的俩个循环改为双向搜索,改进时间复杂度。
- 如果有什么地方不懂可以留言,我会回复答疑