编程之美——快速寻找满足条件的两个数或三个数

编程之美——快速寻找满足条件的两个数或三个数

问题:

1. 快速找出一个数组中的两个数,让这两个数之和等于一个给定的值。

2. 快速找出一个数组中的三个数,让这三个数之和等于一个给定的值。


1. 解法:算法复杂度为O(nlogn)。先用快速排序对数组排序,让后用双指针(双索引)法对排序好的数组进行反向遍历,并且遍历的方向不变。(若是计算两个数的和,则初始化为i=0,j=n-1,若是计算两个数的差,则初始化为i=0,j=1)

之所以这样遍历方式能成功,是因为排序后,若ai+aj<sum,则ai+ak<sum(k=i,i+1...j),而i之前j之后的情况已遍历过,所以只有i++才可能有等号的情况;若ai+aj>sum,则ak+aj>sum(k=i,i+1...j),而i之前j之后的情况已遍历过,所以只有j--才可能有等号的情况。

代码如下:
#include<iostream>
#include<algorithm>
using namespace std;

#define MAXN 1001
int A[MAXN];

int main()
{
  int n,sum,i,j;
  cin>>n>>sum;
  for(i=0;i<n;i++)
 cin>>A[i];
  sort(A,A+n);//快速排序
  i=0;
  j=n-1;
  while(i<j)
  {
    int plus=A[i]+A[j];
if(plus==sum)
{
 cout<<A[i]<<" "<<A[j]<<endl;
 i++;
 j--;
}
else if(plus<sum)
i++;
else
j--;
  }
}


2.解法:时间复杂度为O(n^2)。如果数组已排序,利用解法1的双指针遍历法,可以在O(n)的时间内找到两个数之和等于一个給定的数。我们假设找到的三个数ai,aj,ak有ai<=aj<=ak,要让ai+aj+ak=sum,也就是要ai+aj=sum-ak,设subsum=sum-ak,很容易发现subsum的值只有n个,而确定ai+aj=subsum中的ai,aj只需要O(n)的时间,所以总的时间复杂度为O(nlogn+n*n)=O(n^2)。
代码为:
#include<iostream>
#include<algorithm>
using namespace std;

#define MAXN 1001
int A[MAXN];

int main()
{
  int n,sum,i,j,k;
  cin>>n>>sum;
  for(i=0;i<n;i++)
 cin>>A[i];
  sort(A,A+n);//快速排序
  for(k=0;k<n;k++)
  {
i=0;j=n-1;
if(k==i) i++;
if(k==j) j--;
int subsum=sum-A[k];
    while(i<j)
{
      int plus=A[i]+A[j];
      if(plus==subsum)
 {
  cout<<A[i]<<" "<<A[j]<<" "<<A[k]<<endl;
  i++;
  j--;
 }
 else if(plus<subsum)
i++;
 else
j--;
 if(k==i) i++;
 if(k==j) j--;
  }
}

若允许每个数被多次选取,只需稍微改下代码,具体如下:
#include<iostream>
#include<algorithm>
using namespace std;

#define MAXN 1001
int A[MAXN];

int main()
{
  int n,sum,i,j,k;
  cin>>n>>sum;
  for(i=0;i<n;i++)
 cin>>A[i];
  sort(A,A+n);//快速排序
  for(k=0;k<n;k++)
  {
i=0;j=n-1;
// if(k==i) i++; 
// if(k==j) j--;
int subsum=sum-A[k];
     while(i<j)
{
      int plus=A[i]+A[j];
      if(plus==subsum)
 {
  cout<<A[i]<<" "<<A[j]<<" "<<A[k]<<endl;
  i++;
  j--;
 }
 else if(plus<subsum)
i++;
 else
j--;
//  if(k==i) i++;
//  if(k==j) j--;
  }
}
}
//继续编辑中。。。。。。
参考来源:http://blog.csdn.net/linyunzju/article/details/7720413
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值