编程之法section II: 2.2 和为定值的两个数

数组篇

2.2 求和为定值的两个数:

题目描述:有n个整数,找出其中满足两数相加为target的两个数(如果有多组满足,只需要找出其中一组),要求时间复杂度尽可能低。


解法一:

思路:开散列映射,空间换时间, 查找耗时o(n)

Writer: zzq
Function: 求和为定值的两个数。
方法一: 开散列映射(哈希表)。
1) 用哈希表Hashmap先把数组中的数字和对应的下标进行存储,(键,值)=(具体数值,对应下标);
2) 遍历数组,对loss=target-nums[i],在Hashmap中找是否存在loss,找到即返回loss所对应的value,也就是所对应的数组下标;
时间复杂度:O(n)



#include<iostream>
#include<map>
using namespace std;

//哈希表存储查找  
void twoSum(int *nums, int *result, int length, int target) {    
        map<int, int> hashmap;
        for (int i = 0; i < length; i++)  
            hashmap[nums[i]]=i;  
        map<int, int>::iterator it;
        for (int i = 0; i < length; i++) {  
            int v = target - nums[i];  
            it = hashmap.find(v);
            if(it!=hashmap.end() && i != it->second){  
                result[0] = i;  
                result[1] = hashmap[v];  
                break;  
            }  
        }
}  
int main(){
    int nums[]={10,12,8,56,98,43,21,15,76,19};
    int target = 20;
    int result[2] = {0,0};
    twoSum(nums, result,10, target);
    cout<<result[0]<<' '<<result[1]<<endl;
    return 0;
}

解法二:

思路:快排O(logn)+二分法O(nlogn).

Writer: zzq
Function: 求和为定值的两个数。
方法二: 1)先对给定数组进行排序;
2)在排序好的数组基础上,每次对于loss=target-nums[i],是用二分法查找loss是否存在,如果存在,则返回这两个数;
时间复杂度:O(logn)+O(nlogn),
【 排序:O(logn);
二分查找: O(nlogn)。



#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
// 快速排序 
void QuickSort(int *a, int begin, int end){
	if(begin<end){
		int i = begin;
		int j = end;
		int temp = *(a+i);
		while(i<j){
			while(i<j&&*(a+j)>=temp)j--;
			if(i<j){
				*(a+i)=*(a+j);
				i++;
			}
			while(i<j&&*(a+i)<=temp)i++;
			if(i<j){
				*(a+j)=*(a+i);
				j--;
			}	 
		}
		*(a+i)=temp;
	
	    QuickSort(a,begin,i-1);
		QuickSort(a,i+1,end);
	}
}
 
//二分查找 
int BinaryQuery(int *a,int goal,int start, int end){
	int i=start,j=end;
	int flag = 0;
	while(i<=j){
		int middle = (j-i)/2;		
		if(goal==*(a+middle)){
			return 1;  // 找到目标值
		}
		else if(goal<*(a+middle)){ // 目标值在左半部分 
			j = middle-1;	//  尾下标指向左半部分最后一个元素 		
		}
		else{   // 目标值在右半部分 
			i = middle +1;  // 首指针指向右半部分最后一个元素 
		}		
	}
	return 0;
}
int main(){
	int n,sum;
        cin>>n>>sum;
        int a[n];
        int i;
        for(i = 0;i<n;i++)cin>>a[i];
    
        QuickSort(a,0,n-1); // 快排 
	
        for(i = 0;i < n;i++){
    	    if((sum-a[i])>0){	
    		int flag = BinaryQuery(a,sum-a[i],0, n-1);
			if(flag){
				cout<<a[i]<<' '<<sum-a[i]<<endl;	
				break;
			}	
	    }		
	}	
	return 0;
}

解法三:

思路:快排O(logn)+ two pointers [首尾指针法]O(n).

Writer: zzq
Function: 求和为定值的两个数。
方法二: 1)先对给定数组进行排序;
2)在排序好的数组基础上,每次对于loss=target-nums[i],是用首尾指针法查找loss是否存在,如果存在,则返回这两个数;
时间复杂度:O(logn)+O(nlogn),
【 排序:O(logn);
two pointers: O(n)。




#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
// 快速排序 
void QuickSort(int *a, int begin, int end){
	if(begin<end){
		int i = begin;
		int j = end;
		int temp = *(a+i);
		while(i<j){
			while(i<j&&*(a+j)>=temp)j--;
			if(i<j){
				*(a+i)=*(a+j);
				i++;
			}
			while(i<j&&*(a+i)<=temp)i++;
			if(i<j){
				*(a+j)=*(a+i);
				j--;
			}	 
		}
		*(a+i)=temp;
	
	    QuickSort(a,begin,i-1);
		QuickSort(a,i+1,end);
	}
}
// 首尾指针法
void GetGoalIndex(int *a, int goal,int start,int end){
	int begin = start;
	int last = end;
	
	while(begin<=last){
		int currentSum = *(a+begin)+*(a+last);
		if(currentSum==goal){
			cout<<*(a+begin)<<' '<<*(a+last);
			// 如果需要找到所有满足条件的对数,则需要加上这两行 
			//begin++;
			//last--;
			break;
			
		}
		else{
			if (currentSum>goal){
				last--;
			}
			else{
				begin++;
			}	
		} 
	}	
} 
int main(){
	int n,sum;
    cin>>n>>sum;
    int a[n];
    int i;
    for(i = 0;i<n;i++)cin>>a[i];
    
    QuickSort(a,0,n-1); // 快排 
    GetGoalIndex(a,sum,0, n-1); 
    return 0;
}

举一反三:

找和为定值的两个数的下标,并且两个数不能是同一个。

1:散列表法
2:快排+two pointers(新建数组b跟踪存储下标变化情况)。

void QuickSort(int *a, int *b, int begin, int end){
	//cout<<begin<<' '<<end<<endl;
	if(begin<end){
		int i = begin;
		int j = end;
		int temp = *(a+i);
		int temp_index=*(b+i);	
		while(i<j){
			while(i<j&&*(a+j)>=temp)j--;
			if(i<j){
				*(a+i)=*(a+j);
                *(b+i)=*(b+j);
				i++;
			}
			while(i<j&&*(a+i)<=temp)i++;
			if(i<j){
				*(a+j)=*(a+i);
                *(b+j)=*(b+i);
				j--;
			}	 
		}
		*(a+i)=temp;
        *(b+i)=temp_index;
        //for(int i=0;i<10;i++)cout<<b[i]<<' ';
		//cout<<endl;
	    QuickSort(a, b, begin, i-1);
		QuickSort(a, b, i+1, end);
	}
}
// 寻找下标 ,用数组c接收下标 
void GetGoalIndex(int *a, int *b, int *c, int goal,int start,int end){
	int begin = start;
	int last = end;
	while(begin<=last){
		int currentSum = *(a+begin)+*(a+last);
		if(currentSum==goal){
			if(*(b+begin)>*(b+last)){
				*c=*(b+last);
                *(c+1)=*(b+begin);
			}
			else{
                *c=*(b+begin);
                *(c+1)=*(b+last);
			}	
			break;
		}
		else{
			if (currentSum>goal){
				last--;
			}
			else{
				begin++;
			}	
		} 
	}
} 
int* twoSum(int* nums, int numsSize, int target) {
    int i;
    int b[numsSize];
    static int c[2];
    for(i = 0;i<numsSize;i++){
    	b[i]=i;
	}

    QuickSort(nums, b, 0, numsSize-1);
	//for(int i=0;i<10;i++)cout<<b[i]<<' ';
	//cout<<endl;    
    GetGoalIndex(nums, b, c,target, 0, numsSize-1); 
    return c;    
}
posted @ 2018-06-24 21:28  恩zzq我是  阅读(455)  评论(0编辑  收藏  举报