[LeetCode] 4Sum

这个问题开始的思路还是对的,先求出任意两个数的和,保存这个值以及对应的加数的位置信息。复杂度为O(N^2)。

然后对这些和排序,复杂度估计就到了O(logN*(N^2))。

最后遍历这个序列,找出所有可能的值,暂不讨论这个复杂度。

尽管如此,还是经常超时,经过了一些细节的优化,才勉强通过。

不过通过测试,发现LeetCode对输出的结果的顺序可以匹配,另外这个题的超时时间大概是1s(Java)。

下面是第一个小板凳:

public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
		ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
		if (num.length < 4) {
			return results;
		}
		int length = num.length;
		Set<Integer> sumsOfTwoNumber = new HashSet<Integer>();
		HashMap<Integer, ArrayList<ArrayList<Integer>>> mapForSums = new HashMap<Integer, ArrayList<ArrayList<Integer>>>();

		for (int i = 0; i < length; ++i) {
			int num1 = num[i];
			for (int j = i + 1; j < length; ++j) {
				Integer sum = num1 + num[j];
				sumsOfTwoNumber.add(sum);

				ArrayList<Integer> index = new ArrayList<Integer>(2);
				index.add(i);
				index.add(j);

				ArrayList<ArrayList<Integer>> indexList = mapForSums.get(sum);
				if (indexList != null) {
					indexList.add(index);
				} else {
					indexList = new ArrayList<ArrayList<Integer>>();
					indexList.add(index);
					mapForSums.put(sum, indexList);
				}
			}
		}

		ArrayList<Integer> sumList = new ArrayList<Integer>(sumsOfTwoNumber.size());
		sumList.addAll(sumsOfTwoNumber);
		Collections.sort(sumList);

		HashSet<ArrayList<Integer>> marks = new HashSet<ArrayList<Integer>>();
		int i = 0, j = sumList.size() - 1;
		while (i <= j) {
			int sumA = sumList.get(i);
			int sumB = sumList.get(j);
			int sum4 = sumA + sumB;
			int binary = 2;
			if (sum4 > target) {
				while (true) {
					if (sumA + sumList.get(j - j / binary) > target) {
						j = j - j / (binary) - 1;
						break;
					} else {
						binary *= 2;
						if (binary < 0) {
							--j;
							break;
						}
					}
				}
			} else if (sum4 < target) {
				while (true) {
					if (sumList.get(i + (j - i) / binary) + sumB < target) {
						i = i + (j - i) / (binary) + 1;
						break;
					} else {
						binary *= 2;
						if (binary < 0) {
							++i;
							break;
						}
					}
				}
			} else {
				ArrayList<ArrayList<Integer>> indexes1 = mapForSums.get(sumList
						.get(i));
				ArrayList<ArrayList<Integer>> indexes2 = mapForSums.get(sumList
						.get(j));
				for (int m = 0; m < indexes1.size(); ++m) {
					for (int n = 0; n < indexes2.size(); ++n) {
						TreeSet<Integer> allIndex = new TreeSet<Integer>();
						allIndex.addAll(indexes1.get(m));
						allIndex.addAll(indexes2.get(n));
						if (allIndex.size() == 4) {
							ArrayList<Integer> result = new ArrayList<Integer>();
							Iterator<Integer> iter = allIndex.iterator();
							for (int x = 0; x < 4; ++x) {
								result.add(num[iter.next()]);
							}
							Collections.sort(result);
							marks.add(result);
						}
					}
				}
				if (sumList.get(j) * 2 > target) {
					--j;
				} else {
					++i;
				}
			}
		}
		results.addAll(marks);
		return results;
    }
}
后来发现已经用了hash,不用排序也可以,省了排序的时间,把二分查找去掉,从O(logN*(N^2))降到了O(lN^2),但是由于后面的复杂度比较复杂,整体的复杂度还是比较高。不知道是否把输入中出现4次以上的数可以去掉,但是那样代码就比较长了。

这是新的小板凳,虽然时间只提高了几十ms,但是代码简洁了很多。

public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
		ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
		if (num.length < 4) {
			return results;
		}
		int length = num.length;
		Set<Integer> sumsOfTwoNumber = new HashSet<Integer>();
		HashMap<Integer, ArrayList<ArrayList<Integer>>> mapForSums = new HashMap<Integer, ArrayList<ArrayList<Integer>>>();

		for (int i = 0; i < length; ++i) {
			int num1 = num[i];
			for (int j = i + 1; j < length; ++j) {
				Integer sum = num1 + num[j];
				sumsOfTwoNumber.add(sum);

				ArrayList<Integer> index = new ArrayList<Integer>(2);
				index.add(i);
				index.add(j);

				ArrayList<ArrayList<Integer>> indexList = mapForSums.get(sum);
				if (indexList != null) {
					indexList.add(index);
				} else {
					indexList = new ArrayList<ArrayList<Integer>>();
					indexList.add(index);
					mapForSums.put(sum, indexList);
				}
			}
		}

		ArrayList<Integer> sumList = new ArrayList<Integer>();
		sumList.addAll(sumsOfTwoNumber);
		HashSet<ArrayList<Integer>> marks = new HashSet<ArrayList<Integer>>();
		for (int i = 0; i < sumList.size(); ++i) {
			int sumA = sumList.get(i);
			int sumB = target - sumA;

			ArrayList<ArrayList<Integer>> indexB = mapForSums.get(sumB);
			if (indexB != null) {
				ArrayList<ArrayList<Integer>> indexA = mapForSums.get(sumA);
				for (int m = 0; m < indexA.size(); ++m) {
					for (int n = 0; n < indexB.size(); ++n) {
						TreeSet<Integer> allIndex = new TreeSet<Integer>();
						allIndex.addAll(indexA.get(m));
						allIndex.addAll(indexB.get(n));
						if (allIndex.size() == 4) {
							ArrayList<Integer> result = new ArrayList<Integer>();
							Iterator<Integer> iter = allIndex.iterator();
							for (int x = 0; x < 4; ++x) {
								result.add(num[iter.next()]);
							}
							Collections.sort(result);
							marks.add(result);
						}
					}
				}
			}
		}

		results.addAll(marks);
		return results;
    }
}
看了别人的小板凳后,重写了一下,运行时间又缩减了100ms左右。目前是(716ms)

public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
		ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
		if (num.length < 4) {
			return results;
		}
		int length = num.length;
		HashMap<Integer, ArrayList<ArrayList<Integer>>> mapForSums = new HashMap<Integer, ArrayList<ArrayList<Integer>>>();
		HashSet<ArrayList<Integer>> marks = new HashSet<ArrayList<Integer>>();

		for (int i = 0; i < length; ++i) {
			int num1 = num[i];
			for (int j = i + 1; j < length; ++j) {
				int num2 = num[j];
				int sumA = num1 + num2;

				int sumB = target - sumA;
				ArrayList<ArrayList<Integer>> indexB = mapForSums.get(sumB);
				if (indexB != null) {
					for (int n = 0; n < indexB.size(); ++n) {
						int k = indexB.get(n).get(0);
						int l = indexB.get(n).get(1);
						if (k != i && k != j && l != i && l != j) {
							ArrayList<Integer> result = new ArrayList<Integer>();
							result.add(num1);
							result.add(num2);
							result.add(num[k]);
							result.add(num[l]);
							
							Collections.sort(result);
							marks.add(result);
						}
					}
				}

				ArrayList<Integer> index = new ArrayList<Integer>();
				index.add(i);
				index.add(j);

				ArrayList<ArrayList<Integer>> indexList = mapForSums.get(sumA);
				if (indexList != null) {
					indexList.add(index);
				} else {
					indexList = new ArrayList<ArrayList<Integer>>();
					indexList.add(index);
					mapForSums.put(sumA, indexList);
				}
			}
		}

		results.addAll(marks);
		return results;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值