演算法學習之一:3SUM變體

輕墨發表於2018-08-29

演算法題目

在一個包含n個整數的陣列S中,是否存在三個元素(a,b,c),使得a+b=c?如果存在,給出所有滿足a+b=c的(a,b,c)集合,不能重複。

注意:

  1. 三元素組合(a,b,c),要求(a,b)是升序的,即a<=b
  2. 結果集不能重複

例子:

陣列S = {1, 1, 2, -1, -4},

結果集為:
{-1, 2, 1}
{1, 1, 2}
複製程式碼

思路

這是我面試一個動漫公司遇到的題,是經典3SUM問題的一種變體,整體思路跟3SUM一樣,但略作改變。

第一步,排序,排成降序的,如果S = {1, 1, 2, -1, -4},則排序後為 {2, 1, 1, -1, -4},這一步的時間複雜度為O(nlogn);

第二步,遍歷排序後的陣列,並取遍歷得到的值為c。確定了c以後,接下來問題就變成了,在排序後的陣列中尋找兩個元素之和等於某個數,這是經典的2SUM問題,時間複雜度為O(n)。總共有n次遍歷,每一次的時間複雜度為O(n),因此這一步的時間複雜度為 O(n^2)。

兩步總的時間複雜度為O(nlogn) + O(n^2) = O(n^2)。

亮點

我在學習過程中,特別驚豔於,能在O(n)的時間複雜度內,從有序陣列中尋找兩個元素之和等於某個數。

具體的思路如下:

演算法學習之一:3SUM變體

還是十分巧妙的。

程式碼

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

bool AscendingCompare(int i,int j) { 
    return i > j;
}

class Solution {
public:
	vector<vector<int>> FindSumEqual(vector<int>& array) {
		sort(array.begin(), array.end(), AscendingCompare);
    
		set<vector<int>> results;
		for (int i = 0; i < array.size(); i++) {
			int j = 0;
			int k = array.size() - 1;
			while (j < k) {
				if (array[j] + array[k] == array[i]) {
					results.insert({array[k], array[j], array[i]});
					j++;
					k--;
					while (j < k && array[j] == array[j + 1]) {
						j++;
					}
					while (j < k &&  array[k] == array[k - 1]) {
						k--;
					}
				} else if (array[j] + array[k] > array[i]) {
					j++;
				} else {
					k--;
				}
			}
		}
		vector<vector<int>> results_vector(results.begin(), results.end());

		return results_vector;
	}
}
複製程式碼

演算法學習之一:3SUM變體

相關文章