我有两种不同的经典二和问题解决方案,一种是使用hashmap遍历列表一次,另一种是使用两个索引和一个排序数组来找到解决方案。使用hashmap的时间复杂度是O(n),而另一种方法使用O(nlog(n)),但运行时报告显示使用排序数组比使用map更快。为什么呢?
方法1:使用hashmap
public int[] twoSum(int[] numbers, int target) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < numbers.length; i++) {
if (map.containsKey(target - numbers[i])) {
result[1] = i + 1;
result[0] = map.get(target - numbers[i]);
return result;
}
map.put(numbers[i], i + 1);
}
return result;
}
方法2:使用两个索引和一个排序数组
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] sorted_nums = new int[nums.length];
for(int i = 0; i < nums.length; i++) {
sorted_nums[i] = nums[i];
}
Arrays.sort(sorted_nums);
int begin = 0;
int end = sorted_nums.length - 1;
while(begin < end) {
if(sorted_nums[begin] + sorted_nums[end] == target)
break;
else if(sorted_nums[begin] + sorted_nums[end] > target)
end--;
else
begin++;
}
int[] result = new int[2];
int idx = 0;
for(int i = 0; i < nums.length; i++) {
if(nums[i] == sorted_nums[begin] || nums[i] == sorted_nums[end])
result[idx++] = i;
}
return result;
}
}
答案 0 :(得分:1)
这取决于输入数组大小 - 开销ob装箱/拆箱和额外的内存开销可能太大而无法“擦除渐近的运行时复杂性”
我想测试这里发生了什么,当你在较小的输入上运行很多时,似乎慢速部分是GC。然后GC开销大于更好的渐近复杂度的好处。
我要测试的代码
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class TwoSum {
//run with -Xmx1g
public static void main(String... args) {
for (int sampleSize = 1; sampleSize < 1000; sampleSize*=5) {
for (int size = 10; size <= 40_000_000; size *= 10) {
System.gc();
int[] numbers = new int[size];
int a = 0;
int aa = 1;
for (int i = 0; i < size; i++) {
numbers[i] = a;
a += aa++;
}
Random r = new Random(42);
int[] t = new int[sampleSize];
for (int i = 0; i < sampleSize; i++) {
t[i++] = numbers[r.nextInt(size)] + numbers[r.nextInt(size)];
}
long b = System.currentTimeMillis();
for (int i = 0; i < sampleSize; i++) {
twoSumMap(numbers, t[i]);
}
long c = System.currentTimeMillis();
for (int i = 0; i < sampleSize; i++) {
twoSumArray(numbers, t[i]);
}
long d = System.currentTimeMillis();
System.out.println(
"On size: " + size + " MAP takes: " + (c - b) + " ARRAY takes: " + (d - c) + " with sample size: " + sampleSize);
}
}
}
public static int[] twoSumMap(int[] numbers, int target) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < numbers.length; i++) {
if (map.containsKey(target - numbers[i])) {
result[1] = i + 1;
result[0] = map.get(target - numbers[i]);
return result;
}
map.put(numbers[i], i + 1);
}
return result;
}
public static int[] twoSumArray(int[] nums, int target) {
int[] sorted_nums = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
sorted_nums[i] = nums[i];
}
Arrays.sort(sorted_nums);
int begin = 0;
int end = sorted_nums.length - 1;
while (begin < end) {
if (sorted_nums[begin] + sorted_nums[end] == target)
break;
else if (sorted_nums[begin] + sorted_nums[end] > target)
end--;
else
begin++;
}
int[] result = new int[2];
int idx = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == sorted_nums[begin] || nums[i] == sorted_nums[end])
result[idx++] = i;
}
return result;
}
}
输出:
On size: 10 MAP takes: 0 ARRAY takes: 1 with sample size: 1 On size: 100 MAP takes: 0 ARRAY takes: 0 with sample size: 1 On size: 1000 MAP takes: 1 ARRAY takes: 0 with sample size: 1 On size: 10000 MAP takes: 2 ARRAY takes: 1 with sample size: 1 On size: 100000 MAP takes: 24 ARRAY takes: 4 with sample size: 1 On size: 1000000 MAP takes: 75 ARRAY takes: 90 with sample size: 1 On size: 10000000 MAP takes: 15 ARRAY takes: 862 with sample size: 1 On size: 10 MAP takes: 0 ARRAY takes: 0 with sample size: 5 On size: 100 MAP takes: 0 ARRAY takes: 0 with sample size: 5 On size: 1000 MAP takes: 0 ARRAY takes: 0 with sample size: 5 On size: 10000 MAP takes: 3 ARRAY takes: 0 with sample size: 5 On size: 100000 MAP takes: 107 ARRAY takes: 10 with sample size: 5 On size: 1000000 MAP takes: 144 ARRAY takes: 309 with sample size: 5 On size: 10000000 MAP takes: 45 ARRAY takes: 4167 with sample size: 5 On size: 10 MAP takes: 0 ARRAY takes: 0 with sample size: 25 On size: 100 MAP takes: 0 ARRAY takes: 0 with sample size: 25 On size: 1000 MAP takes: 1 ARRAY takes: 0 with sample size: 25 On size: 10000 MAP takes: 19 ARRAY takes: 2 with sample size: 25 **On size: 100000 MAP takes: 643 ARRAY takes: 36 with sample size: 25** On size: 1000000 MAP takes: 902 ARRAY takes: 1516 with sample size: 25 On size: 10000000 MAP takes: 434 ARRAY takes: 20626 with sample size: 25 On size: 10 MAP takes: 0 ARRAY takes: 0 with sample size: 125 On size: 100 MAP takes: 1 ARRAY takes: 0 with sample size: 125 On size: 1000 MAP takes: 7 ARRAY takes: 1 with sample size: 125 On size: 10000 MAP takes: 104 ARRAY takes: 9 with sample size: 125 **On size: 100000 MAP takes: 2499 ARRAY takes: 148 with sample size: 125** On size: 1000000 MAP takes: 3282 ARRAY takes: 7485 with sample size: 125 On size: 10000000 MAP takes: 1966 ARRAY takes: 102934 with sample size: 125 On size: 10 MAP takes: 0 ARRAY takes: 0 with sample size: 625 On size: 100 MAP takes: 3 ARRAY takes: 1 with sample size: 625 On size: 1000 MAP takes: 34 ARRAY takes: 4 with sample size: 625 **On size: 10000 MAP takes: 485 ARRAY takes: 42 with sample size: 625** **On size: 100000 MAP takes: 12807 ARRAY takes: 734 with sample size: 625** On size: 1000000 MAP takes: 16113 ARRAY takes: 37191 with sample size: 625