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 result of the two numbers such that they add up to the target . Please note that your returned answers (both result1 and result2) are not zero-based.

You may assume that each input would have exactly one solution.

Input: numbers={2, 7, 11, 15}, target=9

Output: result1=2, result2=7

一:若数组无序

方法一,使用双重循环,遍历数组的方法,确定一个数之后查找数组以确定另外一个数是否也存在数组中

/*2:
 * 寻找和为定值的两个数
 * 问题描述:给定一个数组和一个数,要求在数组中找出两个数,使其和为该数,并输出这两个数
 * 
 * 方法一:该算法的时间复杂度为o(n*n),双重循环
 * 分析:
 * 1,给定无序数组T,整数k
 * 2,i=0->T.length   int temp=k-T[i]
 * 3,j=i+1->T.length 	if(temp==T[j])	return T[I],T[j]
 * @param Targent目标无序数组 
 * @param k和值
 * @param 返回值为一个数组,存放结果的两个数
 */
public int[] twoSum1(int[] Targent,int k){
	int[] result=new int[2];
	int temp=0;
	for(int i=0;i<Targent.length;i++){
		temp=k-Targent[i];				//第一个数确定的情况下,求出第二个数
		for(int j=1+i;j<Targent.length;j++){
			if(temp==Targent[j]){		//在数组中寻找第二个数是否存在,若存在,则返回两个数
				result[0]=Targent[i];
				result[1]=Targent[j];
				return result;
			}
		}
	}
	return result;
}
方法二,使用hashmap映射的方法

 

/*
 * 方法四:利用hashMap存放互补数组,将原数组和互补数组作映射,查找hashMap的时间复杂度为O(1),与处理hashMap的时间
 * 复杂度为O(n),故该方法的时间复杂度为O(n),但是需要O(N)的hashMap空间复杂度,在时间复杂度要求比较高的情况下,可以利用
 * 空间换时间!
 * 伪代码:
 * 1,int[] T,int k		int[] R=k-T[i] i=0->T.length
 * 2,hashMap.put(k-T[i],T[i])   i=0->T.length-1		//构造hashMap,key=k-T[i],value=T[i] ,时间复杂度为O(n)
 * 3,if(hashMap.containsKey(T[i]))	return T[i],k-T[i];		//containsKey(key)根据hashMap中是否存在键值,来返回
 * @param Targent为无序或者有序数组
 * @param k为输入和值
 * @param 返回值为二维数组
 */
public int[] twoSum4(int[] Targent,int k){
	int[] result=new int[2];
	//构造hashMap
	Map<Integer, Integer> reflectMap=new HashMap();
	for(int i=0;i<Targent.length;i++){
		//将数组R作为key值,T作为value,时间复杂度为O(n)
		reflectMap.put(k-Targent[i], Targent[i]);
	}
	//根据T[i]查询hashMap,hashMap查询时间复杂度为O(1)
	for(int i=0;i<Targent.length;i++){
		if(reflectMap.containsKey(Targent[i])){
			result[0]=Targent[i];
			result[1]=k-Targent[i];
			return result;
		}
	}
	return result;
}

二:若数组按照升序排列

方法一,在循环遍历的基础上使用二分查找,确定一个数之后,使用二分查找另外一个数是否存在于数组之中

/*
 * 算法优化:二分查找的时间复杂度为O(lgn),最坏情况下需要查找n次,故该算法的时间复杂度为O(nlgn)
 * 					若数组无序,则用快速排序方法进行排序,时间复杂度为O(nlgn),最后总共的时间复杂度为O(nlgn)+O(nlgn)=O(nlgn)
 * 分析:
 * 1,int i=0->T.length  int temp=k-T[i]
 * 2,使用二分查找的方法来寻找temp数值是否在T数组中
 * @param Targent为有序数组
 * @param k为输入和值
 * @param 返回值为二维数组
 */
public int[] twoSum2(int[] Targent,int k){
	int[] result=new int[2];
	int temp=0;
	for(int i=0;i<Targent.length;i++){			//时间复杂度O(n)
		temp=k-Targent[i];
		if(divideQuery(Targent, temp)){			//时间复杂度O(lgn)
			result[0]=Targent[i];
			result[1]=temp;
			return result;
		}
	}
	return result;
}
/*
 * 二分查找:递归实现,时间复杂度为O(lgn)
 * 分析:
 * 1,对于一个有序数组T,所需要查找的数为k
 * 2,int index = (T.length-1)/2		//找到数组中位数的下标指针
 * 3,boolean divideQuery'(int[] Targent, int k, int left, int right)
 * 				if(k<T[index])	return divideQuery(T, k , 0 ,index-1)
 * 				else if(k==T[index])		return true
 * 				else 	return divide	Query(T,  k, index+1, T.length-1)
 * 4,if(left==index&&Targent[index]!=k)	return false;	//递归结束判断
 * @param Targent目标有序数组
 * @param k需要查找的数
 * @param 返回值为boolean ,存在k则返回true ,否则返回false
 */
public  boolean divideQuery(int[] Targent,int k) {
	int firstIndex=Targent.length-1;
	if(k<Targent[0]||k>Targent[firstIndex])
		return false;
	return divideQuery(Targent, k,	0 , firstIndex);
}
private  boolean divideQuery(int[] Targent, int k ,int left ,int right) {
	int index=(right+left)>>1;
	//该判断为递归结束的判断条件,否则递归不能结束
	if(left==index&&Targent[index]!=k)
		return false;
	if(k<Targent[index])
		 return divideQuery(Targent, k, left, index-1);
	else if(k==Targent[index])
		return true;
	else 
		return divideQuery(Targent, k, index+1, Targent.length-1);
}
/*
 * 二分查找:while循环实现,对于有序数组时间复杂度为O(lgn)
 * 伪代码:
 * 1,int left=0,right=T.length-1
 * 2,int index=(left+right)>>1
 * 3,while(left!=right){
 * 			if(T[index]>k){			//若中位数比k大,则说明k在中卫数之前,需要将right指针左移一位
 * 				right=index-1;
 * 				index=(left+right)>>1;}
 * 			else if(T[index]==k)	//若中位数与k相等,则返回找到
 * 				return true
 * 			else{							//若中位数比k小,则说明k在中位数后面,需要将left指针加一
 * 				left=index+1
 * 				index=(left+right)>>1}
 * 			}
 * @param Targent目标有序数组
 */
public boolean divideQuery2(int[] Targent,int k){
	int left=0;
	int right=Targent.length-1;
	int index=(right+left)>>1;
	//此处找到循环条件需要注意left<=right为正确,不能选择left!=right否则
	//当查找到left==right时,循环结束,该条件下没有判断
	while(left<=right){
		if(Targent[index]>k){
			//注意找到中位数之后,right指针需要变动
			right=index-1;
			index=(left+right)>>1;
		}else if(Targent[index]==k)
			return true;
		else{
			//注意找到中位数之后,left指针需要变动
			left=index+1;
			index=(left+right)>>1;
		}
	}
	return false;
}
方法二,可以使用求互补数组的方法,对于升序排列的数组,求出其互补数组,若存在两个数相加等于目标数,则在这两个数组之中一定存在相等的两个数。

/*
 * 求互补数组的方法
 * 算法时间复杂度为O(n),但是需要求出互补数组,故空间复杂度为O(n)
 * 1,若有序数组T中存在两个数a,b 使得a+b=k成立
 * 2,作数组D=k-T[i],则a,b两数一定在数组D中存在
 * 3,定义两个整形变量i,j,使i从T数组左边开始遍历,j从D数组右边开始遍历,若找到相等的数,则返回找到,一直到i=j
 * 例如,若数组T={1,2,4,7,11,15},若k=15,则数组D={14,13,11,8,4,0},4+11=15成立,故若4在数组T中,则在D中也一定存在
 * 伪代码:
 * 1,int T,
 * 2,int D=k-T[i]	i=0->T.length;
 * 3,while(i!=j)
 * 			if(T[i]>D[J])
 * 				J++;
 * 			if(T[i]==D[j])
 * 				return T[i],k-T[i]
 * 			if(T[i]<D[j])
 * 				i++
 * 		return -1
 * @param Targent为无序或者有序数组
 * @param k为输入和值
 * @param 返回值为二维数组
 */
public int[] twoSum3(int[] Targent,int k){
	int[] result=new int[2];
	//计算数组T的差分数组,时间复杂度为O(n)
	int[] minus=new int[Targent.length];
	for(int i=0;i<Targent.length;i++){
		minus[i]=k-Targent[i];
	}
	//定义两个指针
	int i=0;
	int j=Targent.length-1;
	while(i!=j){			//时间复杂度为O(n),遍历指针i+j<=n
		if(Targent[i]==minus[j]){
			result[0]=Targent[i];
			result[1]=k-Targent[i];
			return result;
		}
		if(Targent[i]>minus[j])
			j--;
		if(Targent[i]<minus[j])
			i++;
	}
	return result;
}
方法三,该算法在升序排列的基础上,为最好的算法。

/*
 * 最好的算法,
 * 要求数组为有序数组,此时时间复杂度为O(n),否则先进行排序,时间复杂度为O(NLGN)+O(N)
 * 寻找时间复杂度为O(N),空间复杂度为O(1)的算法
 * 分析:
 * 1,对于数组T,若数组无序,则首先对数组进行排序,时间复杂度为O(nlgn)
 * 2,定义两个指针,left=0,right=T.length-1分别从数组的两端遍历数组
 * 3,若T[left]+T[right]>K,则使right指针左移一位,减小两个数的和值
 * 4,若T[left]+T[right]<K,则使left指针右移一位,增加两个数的和值
 * 5,当指针left=right时,结束循环判断
 * @param Targent为有序数组
 * @param k为输入的数
 * @param 返回值为一个二维数组
 */
public int[] twoSum5(int[] Targent,int k){
	//定义存放结果的数组
	int[] result=new int[2];
	//定义两个指针
	int left=0;
	int right=Targent.length-1;
	//循环控制,判断T[left]+T[right]与K值的大小
	while(left<right){
		if(Targent[left]+Targent[right]>k)
			right--;
		else if(Targent[left]+Targent[right]<k)
			left++;
		else {
			result[0]=Targent[left];
			result[1]=Targent[right];
			return result;
		}
	}
	return result;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值