個人記錄-LeetCode 15. 3Sum
阿新 • • 發佈:2019-01-25
問題:
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1 , 0, 1],
[-1, -1, 2]
]
題目的要求是:
從給定的陣列中找到不重複的組合。
每個組合包含3個元素,其和為0。
程式碼示例:
1、暴力解法
public class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
if (nums == null || nums.length < 3 ) {
return result;
}
int len = nums.length;
//現將給定陣列從小到大排序
Arrays.sort(nums);
//最小值大於0或最大值小於0,顯然是無法找到需要的組合
if (nums[0] > 0 || nums[len-1] < 0) {
return result;
}
//考慮到組合的和為0,因此整個組合不可能全部為負數或正數
//用於儲存負數,及負數出現的次數
HashMap<Integer, Integer> negativeMap = new HashMap<>();
ArrayList<Integer> negativeList = new ArrayList<>();
//用於儲存正數,及正數出現的次數
HashMap<Integer, Integer> positiveMap = new HashMap<>();
ArrayList<Integer> positiveList = new ArrayList<>();
//儲存是否出現0
int numOfZero = 0;
for (int num : nums) {
if (num < 0) {
addNumToCollections(num, negativeMap, negativeList);
} else if (num > 0) {
addNumToCollections(num, positiveMap, positiveList);
} else {
++numOfZero;
}
}
//出現3個以上的0,顯然0 0 0的組合滿足條件
if (numOfZero >= 3) {
List<Integer> answer = new ArrayList<>();
for (int i = 0; i < 3; ++i) {
answer.add(0);
}
result.add(answer);
}
//每次先取一個負數,再取一個正數
for (int i = 0; i < negativeList.size(); ++i) {
for (int j = 0; j < positiveList.size(); ++j) {
int negative = negativeList.get(i);
int positive = positiveList.get(j);
//求出需要的第3個數
int complete = 0 - negative - positive;
boolean addFlag = false;
//需要的數小於0,並且存在
if (complete < 0 && negativeMap.containsKey(complete)) {
//需要的數與主動取出的負數不一致時,它的下標必須大於主動取得負數的下標,否則會出現重複的組合
if ((complete != negative && negativeList.indexOf(complete) > i)||
//需要的數與主動取出的負數一致,那麼要求這個負數至少出現兩次以上
(complete == negative && negativeMap.get(negative) > 1)) {
addFlag = true;
}
//所需的數為正數,類似
} else if (complete > 0 && positiveMap.containsKey(complete)){
if ((complete != positive && positiveList.indexOf(complete) > j)
|| (complete == positive && positiveMap.get(positive) > 1)) {
addFlag = true;
}
} else if (complete == 0 && numOfZero > 0){
addFlag = true;
}
if (addFlag) {
addAnswerToResult(negative, positive, complete, result);
}
}
}
return result;
}
private void addNumToCollections(int num, Map<Integer, Integer> map, List<Integer> list) {
if (map.containsKey(num)) {
map.replace(num, map.get(num), map.get(num)+1);
} else {
map.put(num, 1);
list.add(num);
}
}
private void addAnswerToResult(int negative, int positive, int complement, List<List<Integer>> result) {
List<Integer> answer = new ArrayList<>();
answer.add(negative);
answer.add(positive);
answer.add(complement);
result.add(answer);
}
}
這個方法可以得到正確結果,但是會超時。整個演算法僅看for迴圈似乎複雜度是O(
public class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
if (nums == null || nums.length < 3) {
return result;
}
int len = nums.length;
Arrays.sort(nums);
if (nums[0] > 0 || nums[len-1] < 0) {
return result;
}
//輪詢陣列中的每一個數字,為了避免重複
//找到在這個數字之後,出現的另外兩個數字,構成組合
for (int i = 0; i < len-2;) {
int firstIndex = i + 1;
int lastIndex = len - 1;
while (firstIndex < lastIndex) {
int curr = nums[firstIndex] + nums[lastIndex] + nums[i];
//類似於求水位問題,當前的和大於0,降低高位的下標
if (curr > 0) {
do {
--lastIndex;
//跳過重複的值
} while (firstIndex < lastIndex && nums[lastIndex] == nums[lastIndex+1]);
//當前的和小於0,增加低位的下標
} else if (curr < 0){
do {
++firstIndex;
} while(firstIndex < lastIndex && nums[firstIndex] == nums[firstIndex-1]);
} else {
addAnswerToResult(nums[firstIndex], nums[lastIndex], nums[i], result);
//等於0時,找出新的兩個數,與當前數字構成組合
//低位增加、高位減小才有可能滿足條件
do {
++firstIndex;
}while(firstIndex < lastIndex && nums[firstIndex] == nums[firstIndex-1]);
do {
--lastIndex;
}while (firstIndex < lastIndex && nums[lastIndex] == nums[lastIndex+1]);
}
}
//跳過重複的組合
do{
++i;
}while(i < nums.length && nums[i] == nums[i-1]);
}
return result;
}
private static void addAnswerToResult(int first, int last, int complement, List<List<Integer>> result) {
List<Integer> answer = new ArrayList<>();
answer.add(first);
answer.add(last);
answer.add(complement);
result.add(answer);
}
}
這個方法的複雜度是O(