思路1:可以用hash表来存储数组中的元素,这样我们取得一个数后,去判断sum - val 在不在数组中,如果在数组中,则找到了一对二元组,它们的和为sum,该算法的缺点就是需要用到一个hash表,增加了空间复杂度。
思路2:同样是基于查找,我们可以先将数组排序,然后依次取一个数后,在数组中用二分查找,查找sum -val是否存在,如果存在,则找到了一对二元组,它们的和为sum,该方法与上面的方法相比,虽然不用实现一个hash表,也没不需要过多的空间,但是时间多了很多。排序需要O(nLogn),二分查找需要(Logn),查找n次,所以时间复杂度为O(nLogn)。
思路3:该方法基于第2种思路,但是进行了优化,在时间复杂度和空间复杂度是一种折中,但是算法的简单直观、易于理解。首先将数组排序,然后用两个指向数组的指针,一个从前往后扫描,一个从后往前扫描,记为first和last,如果 fist + last < sum 则将fist向前移动,如果fist + last > sum,则last向后移动。
- #include <iostream>
- #include <algorithm>
- using namespace std;
- void printPairSums(int data[], int size, int sum);
- int main(int argc, char* argv[])
- {
- int data[] = {1, 5, 9, -1, 4, 6, -2, 3, -8};
- int size = sizeof(data) / sizeof(data[0]);
- int i;
- sort(data, data + size);
- printPairSums(data, size, 8);
- return 0;
- }
- void printPairSums(int data[], int size, int sum)
- {
- int first = 0;
- int last = size -1;
- int s = 0;
- while (first < last)
- {
- s = data[first] + data[last];
- if (s == sum)
- {
- cout << data[first] << " + " << data[last] << " = " << sum << endl;
- first++;
- last--;
- }
- else if (s < sum)
- {
- first++;
- }
- else
- {
- last--;
- }
- }
- }
思路: 对于二元组的和等于给定值的情况,可以参考http://blog.csdn.net/lalor/article/details/7554594, 即将数组排序后,用两个指向数组的指针,一个从前向后扫描,一个从后向前扫描,记为first和last,当first + last == sum 则找到了一对二元组,它们的和等于sum,如果first + last < sum 则 first++, first + last > sum 则last--。同样,三元组的情况,先将数组排序,然后固定一个元素,再去寻找一个二元组的和为sum - val,这样就将三元组的问题,转换成了二元组的问题。
程序如下:
- #include <iostream>
- #include <algorithm>
- using namespace std;
- bool find3Numbers(int A[], int arr_size, int sum)
- {
- int l, r;
- /* Sort the elements */
- sort(A, A + arr_size);
- /* Now fix the first element one by one and find the
- * other two elements
- */
- for (int i = 0; i < arr_size - 2; i++)
- {
- // to find the other two elements, start two index variables
- //from two corners of the array and move toward each other
- l = i + 1; //index of the first element in the remaining elements
- r = arr_size - 1;//index of the last element
- while (l < r)
- {
- if (A[i] + A[l] + A[r] == sum)
- {
- cout << "Triplet is\t" << A[i] << "\t" << A[l] << "\t" << A[r] << endl;
- return true;
- }
- else if (A[i] + A[l] + A[r] < sum)
- {
- l++;
- }
- else // A[i] + A[l] + A[r] > sum
- {
- r--;
- }
- }
- }
- // If we reach here, then no triplet was found
- return false;
- }
- /* Driver program to test above function */
- int main(int argc, char* argv[])
- {
- int A[] = {1, 4, 45, 6, 10, 8};
- int sum = 22;
- int arr_size = sizeof(A) / sizeof(A[0]);
- find3Numbers(A, arr_size, sum);
- return 0;
- }
方法2(回溯法),也能得到不错的效率
- #include <iostream>
- #include <algorithm>
- using namespace std;
- const int S = 22;
- int sumCheck(int A[], int start, int end, int arr[], int cnt)
- {
- if (cnt == 2)
- {
- int sum = arr[0] + arr[1] + arr[2];
- if (sum == S)
- {
- cout << arr[0] << "\t" << arr[1] << "\t" << arr[2] << endl;
- }
- return 0;
- }
- if (start > end || cnt > 2)
- {
- return -1;
- }
- int i = start;
- arr[++cnt] = A[i];
- sumCheck(A, start + 1, end, arr, cnt);
- arr[cnt] = 0;
- cnt--;
- sumCheck(A, start + 1, end, arr, cnt);
- }
- /* Driver program to test above function */
- int main(int argc, char* argv[])
- {
- int A[] = {1, 4, 45, 6, 10, 8};
- int arr_size = sizeof(A) / sizeof(A[0]);
- int cnt = -1;
- int arr[3] = {0, 0, 0};
- sumCheck(A,0, arr_size-1, arr, cnt);
- return 0;
- }