题目:
http://www.leetcode.com/2010/04/finding-all-unique-triplets-that-sums.html
分析:
首先brute force,O(n3)。i j k从0到n-1各循环一遍,肯定不能要。
其次,我们先假设只有2个数,对于一个排序的数组来说,如果想要a + b = 0,那么可以两个指针,一个在head(),一个在tail(),然后判断这两个it的值相加是否等于0,如果小于,那么前面的指针++,如果大于,那么后面的指针--,直到指针相遇或者找到和为0的一对。这使得2个数字的算法复杂度由O(n2) -> O(n)。
然后,对于3个数字的相加,先变为 a + b = -c; 那么,对于其中一个数,做一个O(n)的遍历,剩下两个数进行一个算法复杂度的降低(O(n2) -> O(n))。得到如下代码:
set<vector<int> > threeSum(vector<int> &num) { sort(num.begin(), num.end()); set< vector<int> > triplets; vector<int> triplet(3); int n = num.size(); for (int i = 0; i < n; i++) { int j = i + 1; int k = n - 1; while (j < k) { if (num[j] + num[k] < 0 - num[i]) j++; else if (num[j] + num[k] > 0 - num[i]) k--; else { vector<int>::iterator it = triplet.begin(); *it++ = num[i]; *it++ = num[j]; *it++ = num[k]; j++; k--; triplets.insert(triplet); } } } return triplets; }
最终的复杂度为O(n2)。
另外转载一篇从网上看来的,返回值是vector< vector<int> >的解法,非常好!在LeetCode Online Judge上不会超时:
http://www.cnblogs.com/codingmylife/archive/2012/08/30/2663796.html
它的思想是手动过滤重复。
// Dedup directly, // LeetCode Judge Large, 272 milli secs. vector<vector<int> > three_sum(vector<int> &num) { vector<vector<int> > ret; if (num.size() == 0) return ret; sort(num.begin(), num.end()); for (vector<int>::const_iterator it = num.begin(); it != num.end(); ++it) { // Dedup if (it != num.begin() && *it == *(it - 1)) { continue; } // Dedup, front = it + 1 vector<int>::const_iterator front = it + 1; vector<int>::const_iterator back = num.end() - 1; while (front < back) { const int sum = *it + *front + *back; if (sum > 0) { --back; } else if (sum < 0) { ++front; } // Dedup else if (front != it + 1 && *front == *(front - 1)) { ++front; } // Dedup else if (back != num.end() - 1 && *back == *(back + 1)) { --back; } else { vector<int> result; // Already sorted. result.push_back(*it); result.push_back(*front); result.push_back(*back); ret.push_back(result); ++front; --back; } } } return ret; }
EOF