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

Posted 恩zzq我是

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编程之法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;    
}

以上是关于编程之法section II: 2.2 和为定值的两个数的主要内容,如果未能解决你的问题,请参考以下文章

和为定值的m个数

和为定值的多个数

寻找和为定值的两个数

和为定值的两个数

算法笔记_037:寻找和为定值的两个数(Java)

使用java,列举所有给定数组中和为定值的组合