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

问题:

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--才可能有等号的情况。

  1. #include <iostream>   
  2. #include <algorithm>   
  3. using namespace std;  
  4.   
  5. #define MAXN 1001   
  6. int A[MAXN];  
  7.   
  8. // 总的时间复杂度为O(nlogn)   
  9. int main()  
  10. {  
  11.     int n, sum, i, j;  
  12.     cin >> n >> sum;  
  13.     for (i=0; i<n; i++)  
  14.         cin >> A[i];  
  15.     // 快速排序O(nlogn)   
  16.     sort(A, A+n);  
  17.     // 双索引反向遍历   
  18.     i=0; j=n-1;  
  19.     // 每个数只能用一次(若每个数可以用多次,则用<=)   
  20.     while (i<j)  
  21.     {  
  22.         int plus = A[i]+A[j];  
  23.         if (plus == sum)  
  24.         {  
  25.             printf("(%d,%d) ",A[i],A[j]);  
  26.             i++, j--;  
  27.         }  
  28.         else if (plus < sum)  
  29.             i++;  
  30.         else  
  31.             j--;  
  32.     }  
  33. }  
#include <iostream>
#include <algorithm>
using namespace std;

#define MAXN 1001
int A[MAXN];

// 总的时间复杂度为O(nlogn)
int main()
{
	int n, sum, i, j;
	cin >> n >> sum;
	for (i=0; i<n; i++)
		cin >> A[i];
	// 快速排序O(nlogn)
	sort(A, A+n);
	// 双索引反向遍历
	i=0; j=n-1;
	// 每个数只能用一次(若每个数可以用多次,则用<=)
	while (i<j)
	{
		int plus = A[i]+A[j];
		if (plus == sum)
		{
			printf("(%d,%d) ",A[i],A[j]);
			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)

  1. #include <iostream>   
  2. #include <algorithm>   
  3. using namespace std;  
  4.   
  5. #define MAXN 1001   
  6. int A[MAXN];  
  7.   
  8. int main()  
  9. {  
  10.     int n, sum, i, j, k;  
  11.     cin >> n >> sum;  
  12.     for (i=0; i<n; i++)  
  13.         cin >> A[i];  
  14.     sort(A, A+n);  
  15.     for (k=0; k<n; k++)  
  16.     {  
  17.         i=0; j=k-1;  
  18.         if (k==i) i++;  
  19.         if (k==j) j--;  
  20.         int subsum = sum-A[k];  
  21.         while (i<j)  
  22.         {  
  23.             int plus = A[i]+A[j];  
  24.             if (plus == subsum)  
  25.             {  
  26.                 printf("(%d,%d,%d) ",A[i],A[j],A[k]);  
  27.                 i++, j--;  
  28.             }  
  29.             else if (plus < subsum)  
  30.                 i++;  
  31.             else  
  32.                 j--;  
  33.             if (k==i) i++;  
  34.             if (k==j) j--;  
  35.         }  
  36.     }  
  37. }  
#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=k-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)
			{
				printf("(%d,%d,%d) ",A[i],A[j],A[k]);
				i++, j--;
			}
			else if (plus < subsum)
				i++;
			else
				j--;
			if (k==i) i++;
			if (k==j) j--;
		}
	}
}

若允许每个数被多次选取,只需稍微改下代码,具体如下:

  1. #include <iostream>   
  2. #include <algorithm>   
  3. using namespace std;  
  4.   
  5. #define MAXN 1001   
  6. int A[MAXN];  
  7.   
  8. int main()  
  9. {  
  10.     int n, sum, i, j, k;  
  11.     cin >> n >> sum;  
  12.     for (i=0; i<n; i++)  
  13.         cin >> A[i];  
  14.     sort(A, A+n);  
  15.     for (k=0; k<n; k++)  
  16.     {  
  17.         i=0; j=k;  
  18.         //if (k==i) i++;   
  19.         //if (k==j) j--;   
  20.         int subsum = sum-A[k];  
  21.         while (i<=j)  
  22.         {  
  23.             int plus = A[i]+A[j];  
  24.             if (plus == subsum)  
  25.             {  
  26.                 printf("(%d,%d,%d) ",A[i],A[j],A[k]);  
  27.                 i++, j--;  
  28.             }  
  29.             else if (plus < subsum)  
  30.                 i++;  
  31.             else  
  32.                 j--;  
  33.             //if (k==i) i++;   
  34.             //if (k==j) j--;   
  35.         }  
  36.     }  
  37. }  

本文出自: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、付费专栏及课程。

余额充值