TwoSum:两数相加得0

在一个不重复的数组中,统计有多少组两个元素相加得0。

这里使用三种方式实现,并统计他们各自花费的时间:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;

public class TwoSum {
	private static int N = 100000;
	private static int[] a = new int[N];
	private static Random random = new Random();
	private static HashMap<Integer, Boolean> m = new HashMap<Integer, Boolean>();
	
	private int binarySearch(int[] a, int num) {
		int low = 0, mid = 0, high = a.length - 1;
		while (low <= high) {
			mid = low + (high - low) / 2;
			if (a[mid] > num) {
				high = mid - 1;
			} else if (a[mid] < num) {
				low = mid + 1;
			} else {
				return mid;
			}
		}
		
		return -1;
	}
	
	public int solution1() {
		int count = 0;
		for (int i = 0; i < N; i++) {
			for (int j = i + 1; j < N; j++) {
				if (a[i] + a[j] == 0) {
					count++;
				}
			}
		}
		return count;
	}
	
	public int solution2() {
		int count = 0;
		Arrays.sort(a);
		for (int i = 0; i < N; i++) {
			if (binarySearch(a, -a[i]) > i) {
				count++;
			}
		}
		return count;
	}
	
	public int solution3() {
		int count = 0;
		for (int i = 0; i < N; i++) {
			if (m.containsKey(-a[i])) {
				count++;
			}
		}
		return count / 2;
	}
	
	public static int uniform(int N) {
        if (N <= 0) throw new IllegalArgumentException("Parameter N must be positive");
        return random.nextInt(N);
    }
	
	public int uniform(int a, int b) {
        if (b <= a) throw new IllegalArgumentException("Invalid range");
        if ((long) b - a >= Integer.MAX_VALUE) throw new IllegalArgumentException("Invalid range");
        return a + uniform(b - a);
    }
	
	public static void main(String[] args) {
		TwoSum ts = new TwoSum();
		int count = 0;
		int rand = 0;
		int i = 0;
		boolean flag = true;
		
		while (i < a.length) {
			rand = ts.uniform(-10000000, 10000000);
			flag = true;
			for (int j = 0; j < a.length; j++) {
				if (a[j] == rand) {
					flag = false;
					break;
				}
			}
			if (flag) {
				a[i] = rand;			
				i++;
				//System.out.println(rand + " " + flag);
			}
		}
		
		for (int j = 0; j < N; j++) {
			m.put(a[j], true);
		}
		
		Stopwatch timer1 = new Stopwatch();
		count = ts.solution1();
		double time = timer1.elapsedTime();
		System.out.println("count1: " + count + " cost1: " + time);
		
		count = 0;
		time = 0;
		Stopwatch timer2 = new Stopwatch();
		count = ts.solution2();
		time = timer2.elapsedTime();
		System.out.println("count2: " + count + " cost2: " + time);
		
		count = 0;
		time = 0;
		Stopwatch timer3 = new Stopwatch();
		count = ts.solution3();
		time = timer3.elapsedTime();
		System.out.println("count3: " + count + " cost3: " + time);
	}
}

solution1:直接使用一个两层for循环,所以最终的时间复杂度为O(N^2);

solution2:先将数组排序,然后通过二分查找来搜索数组中每个元素的相反数,此时的时间复杂度为O(N*log(N));

solution3:和方法一类似,只不过是通过哈希表中查找元素的复杂度为O(1)来优化搜索时间,此时时间复杂度为O(N);

当N=1000时

count1: 0 cost1: 0.004
count2: 0 cost2: 0.002
count3: 0 cost3: 0.001

当N=10000时

count1: 5 cost1: 0.026
count2: 5 cost2: 0.009
count3: 5 cost3: 0.005

当N=100000时

count1: 238 cost1: 2.296
count2: 238 cost2: 0.077
count3: 238 cost3: 0.012

这里因为产生不重复的随机数使用的是最简单的两层循环,所以当数组的length太大时,比如1000000时,在产生随机数的过程中会消耗很长时间,这一部分可以使用其他更优的方法实现。

------------------------------- 问道,修仙 -------------------------------
原文地址:https://www.cnblogs.com/elvalad/p/4060991.html