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时,在产生随机数的过程中会消耗很长时间,这一部分可以使用其他更优的方法实现。

时间: 2024-10-06 01:59:22

TwoSum:两数相加得0的相关文章

【LeetCode】- Two Sum(两数相加)

[ 问题: ] Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please no

leetCode:twoSum 两数之和 【JAVA实现】

LeetCode 两数之和 给定一个整数数组,返回两个数字的索引,使它们相加到特定目标. 您可以假设每个输入只有一个解决方案,并且您可能不会两次使用相同的元素. 更多文章查看个人博客 个人博客地址:twoSum 两数之和 [JAVA实现] 方法一 使用双重循环两两相加判断是否等于目标值 public List<String> twoSum2(int[] arr, int sum) { if (arr == null || arr.length == 0) { return new ArrayL

[CareerCup] 18.1 Add Two Numbers 两数相加

18.1 Write a function that adds two numbers. You should not use + or any arithmetic operators. 这道题让我们实现两数相加,但是不能用加号或者其他什么数学运算符号,那么我们只能回归计算机运算的本质,位操作Bit Manipulation,我们在做加法运算的时候,每位相加之后可能会有进位Carry产生,然后在下一位计算时需要加上进位一起运算,那么我们能不能将两部分拆开呢,我们来看一个例子759+674 1.

程序猿之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)

主要内容:无符号和有符号之间转换.两数相加溢出后数值计算 #include <stdio.h> /* 这个函数存在潜在漏洞 */ float sum_elements(float a[], unsigned length) { int i; float result = 0; for(i = 0; i <= length - 1; i++) { result += a[i]; printf("a[%d] = %f \n",i,a[i]); } return resul

程序员之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)

主要内容:无符号和有符号之间转换.两数相加溢出后数值计算 #include <stdio.h> /* 这个函数存在潜在漏洞 */ float sum_elements(float a[], unsigned length) { int i; float result = 0; for(i = 0; i <= length - 1; i++) { result += a[i]; printf("a[%d] = %f \n",i,a[i]); } return resul

leetcode 2. 两数相加

给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val

【leetcode】 算法题2 两数相加

问题 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 代码实现 #include <vector> #include <map> #include <iostream>

链表表示的两数相加

给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表.你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 代码一: 1 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 2 ListNode res

leetcode刷题2:两数相加add_two_numbers

题目:两数相加 (难度:中等) 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字. 将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807 思路: 本题的思路很简单,按照小学数学中学习的加法原理从末尾到首位,对每一位对齐相加即可. 技巧在于如何处理不同长度的数字