我正在研究3 Sum以自己实现它,并且遇到了以下实施规则:
给定n个整数的数组S,S中是否有元素a,b,c,a + b + c = 0?找到数组中所有唯一的三元组,它们总和为零。
注意:三元组(a,b,c)中的元素必须按非降序排列。 (即a≤b≤c) 解决方案集不得包含重复的三元组。
For example, given array S = {-1 0 1 2 -1 -4},
A solution set is:
(-1, 0, 1)
(-1, -1, 2)
实现(对数组进行排序,遍历列表,并使用另外两个指针来接近目标):
import java.util.*;
public class ThreeSum {
List<List<Integer>> threeSum(int[] num) {
Arrays.sort(num);
List<List<Integer>> res = new LinkedList<>();
for (int i=0; i<num.length-2; i++) {
if (i==0 || (i>0 && num[i] != num[i-1])) { //HERE
int lo = i+1;
int hi = num.length-1;
int sum = 0 - num[i];
while (lo < hi) {
if (num[lo] + num[hi] == sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
while (lo < hi && num[lo] == num[lo+1]) lo++; //HERE
while (lo < hi && num[hi] == num[hi-1]) hi--; //HERE
lo++; hi--;
} else if (num[lo] + num[hi] < sum) lo++;
else hi--;
}
}
}
return res;
}
//Driver
public static void main(String args[]) {
ThreeSum ts = new ThreeSum();
int[] sum = {-1, 0, 1, 2, -1, -4};
System.out.println(ts.threeSum(sum));
}
}
我的问题是(位于评论://这里),检查num[i] != num[i-1]
,num[lo] == num[lo+1]
和num[hi] == num[hi-1]
的原因是什么?据说他们应该跳过相同的结果,但这意味着什么?例子真的会有所帮助。
提前感谢您,并接受回答/投票。
答案 0 :(得分:1)
想象一下你有{-1,-1,0,1,2,4}
并考虑三元组[0],num [2],num [3]( - 1,0,1)。
lo=0
在这里。要排除具有相同值的三元组num [1],num [2],num [3],我们应该增加lo
并传递重复
答案 1 :(得分:1)
这将阻止列表具有重复的三元组。
例如,随你测试:
int[] sum = {-1, 0, 1, 2, -1, -4};
的排序方式如下:
sum = {-4, -1, -1, 0, 1, 2};
您看到自己有-1
两次。如果没有这些测试,如果-1 = 0 + 1
,您将测试两次。这没用,所以算法只搜索下一个不同的值。
您可以删除已排序列表中的副本以阻止这些测试。
感谢MBo,我们无法删除重复项,因为我们可以使用相同值的三元组(但索引不同)
答案 2 :(得分:1)
所有三个句子用于避免重复输出。
考虑排序列表
docker swarm join
如果没有检查{-2, -2 , 1, 1}
,则该计划的输出将是num[i] != num[i-1]
和(-2, 1, 1)
,
这两个重复的三元组。<登记/>
检查(-2, 1, 1)
和num[lo] != num[lo + 1]
的原因相同。
考虑一个排序列表
num[hi] != num[hi - 1]
如果没有检查num [lo],您将获得{-2,-1,-1,0,3}
和(-2,-1,3)
作为输出。
不过,我想为这个问题推荐一个更好的解决方案。您可以计算列表中两个数字的总和,并通过散列或二进制搜索找到第三个数字。它将帮助您获得O(n ^ 2logn)时间复杂度而不是O(n ^ 3)。 (我错了,这个算法的时间复杂度是O(n ^ 2),对不起。)
答案 3 :(得分:1)
以下程序找到具有O(N * 2)
的三个整数对排序后的线性时间的两个总和 - &gt; https://stackoverflow.com/a/49650614/4723446
公共课ThreeSum {
button {
display: inline-block;
margin: 0 auto;
}
}
答案 4 :(得分:1)
它适用于任何 NSum(3Sum、4Sum、5Sum 等)并且速度非常快。
public class ThreeSum {
private static final int RANDOM_RANGE = 20;
private Integer array[];
private Integer arrayIndex[];
private int result[];
private int bagLength;
private int resultIndex = 0;
private void generateData(int size) {
array = new Integer[size];
Random random = new Random();
for (int i = 0; i < size; i++) {
array[i] = random.nextInt(RANDOM_RANGE) - (RANDOM_RANGE/2);
}
}
private void markArrayIndex(int size) {
arrayIndex = new Integer[size];
for (int i = 0; i < size; i++) {
arrayIndex[i] = i;
}
}
private void prepareBeforeCalculate(int size, int sumExpected, int bagLength) {
this.bagLength = bagLength;
result = new int[bagLength];
generateData(size);
markArrayIndex(size);
}
void calculate(int size, int sumExpected, int bagLength) {
prepareBeforeCalculate(size, sumExpected, bagLength);
Arrays.sort(arrayIndex, (l, r) -> array[l].compareTo(array[r]));
System.out.println(Arrays.toString(array));
long startAt = System.currentTimeMillis();
if (sumExpected > 0) findLeft(sumExpected, 0, 0, array.length);
else findRight(sumExpected, 0, 0 - 1, array.length - 1);
System.out.println("Calculating in " + ((System.currentTimeMillis() - startAt) / 1000));
}
private void findLeft(int total, int indexBag, int left, int right) {
while (left < array.length && array[arrayIndex[left]] < 0 && indexBag < bagLength) {
navigating(total, arrayIndex[left], indexBag, left, right);
left++;
}
}
private void findRight(int total, int indexBag, int left, int right) {
while (right >= 0 && array[arrayIndex[right]] >= 0 && indexBag < bagLength) {
navigating(total, arrayIndex[right], indexBag, left, right);
right--;
}
}
private void navigating(int total, int index, int indexBag, int left, int right) {
result[indexBag] = index;
total += array[index];
if (total == 0 && indexBag == bagLength - 1) {
System.out.println(String.format("R[%d] %s", resultIndex++, toResultString()));
return;
}
if (total > 0) findLeft(total, indexBag + 1, left + 1, right);
else findRight(total, indexBag + 1, left, right - 1);
}
private String toResultString() {
int [] copyResult = Arrays.copyOf(result, result.length);
Arrays.sort(copyResult);
int iMax = copyResult.length - 1;
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(array[copyResult[i]]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
}
public class ThreeSumTest {
@Test
public void test() {
ThreeSum test = new ThreeSum();
test.calculate(100, 0, 3);
Assert.assertTrue(true);
}
}