编程之法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;
}

原文地址:https://www.cnblogs.com/zzq-123456/p/9221823.html

时间: 2024-08-08 18:08:29

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

我的新书《编程之法:面试和算法心得》已经上市

我的新书<编程之法:面试和算法心得>已经上市 经过一天一天.一月一月.一年一年漫长的等待,我的新书终于上架开卖了! 异步社区:http://www.epubit.com.cn/book/details/4051.互动出版网(7.7折且包邮且移动端首单再减5元):http://product.china-pub.com/4880112.京东预售:http://item.jd.com/11786791.html,很快就能抢购. 1 新书上市7天 10月13日晚上,拿到<编程之法>第一本

编程之法:面试和算法心得(寻找和为定值的多个数)

内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 输入两个整数n和sum,从数列1,2,3.......n 中随意取几个数,使其和等于sum,要求将其中所有的可能组合列出来. 分析与解法 解法一 注意到取n,和不取n个区别即可,考虑是否取第n个数的策略,可以转化为一个只和前n-1个数相关的问题. 如果取第n个数,那么问题就转化为"取前n-1个数使得它们的和为sum-n",对应的代码语句就是sumOfkNumber(sum - n, n - 1): 如果

编程之法:面试和算法心得(荷兰国旗)

内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 拿破仑席卷欧洲大陆之后,代表自由,平等,博爱的竖色三色旗也风靡一时.荷兰国旗就是一面三色旗(只不过是横向的),自上而下为红白蓝三色. 该问题本身是关于三色球排序和分类的,由荷兰科学家Dijkstra提出.由于问题中的三色小球有序排列后正好分为三类,Dijkstra就想象成他母国的国旗,于是问题也就被命名为荷兰旗问题(Dutch National Flag Problem). 下面是问题的正规描述: 现有n个红白蓝

网络编程之TCP编程

html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption

Hadoop高级编程之为Hadoop实现构建企业级安全解决方案

本章内容提要 ●    理解企业级应用的安全顾虑 ●    理解Hadoop尚未为企业级应用提供的安全机制 ●    考察用于构建企业级安全解决方案的方法 第10章讨论了Hadoop安全性以及Hadoop中用于提供安全控制的机制.当构建企业级安全解决方案(它可能会围绕着与Hadoop数据集交互的许多应用程序和企业级服务)时,保证Hadoop自身的安全仅仅是安全解决方案的一个方面.各种组织努力对数据采用一致的安全机制,而数据是从采用了不同安全策略的异构数据源中提取的.当这些组织从多个源获取数据,接

编程之美2.13 子数组最大乘积

问题描述: 给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合乘积中最大的一组,并写出算法的时间复杂度. 解法: 1.暴力解法------O(n^2) 2.前后缀法------O(n) 3.统计法--------O(n) 具体思路和代码: 1.暴力解法: 思路:利用两层循环,依次删掉一个,其余的做乘法,计算出最大的. 代码: 1 int s1(int A[], int n) 2 { 3 int s = 1; 4 int max; 5 for(int i = 1;

Java 编程之美:并发极速赛车平台出租编程高级篇

借用 Java 并发极速赛车平台出租haozbbs.comQ1446595067 编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了. 相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作的顺序是不可预期的. 并发编程相比 Java 中其他知识点学习起来门槛相对较高,学习起来比较费劲,从而导致很多人望而却步: 而无论是职场面试和高并发高流量的系统的实现却都还离不开并发编程,从而导致能够真正掌握并发编程的人才成为市场比较迫

学习编程之Python篇(一)

第一次接触编程,你将面对两大难题: 1.  对所要使用的编程语言的语法和语义不甚了了. 2.  不知道如何通过编程来解决问题. 作为一名新手,你会尝试同时来解决这两个难题:一边熟悉编程语言的语法语义,一边考虑如何靠编程解决问题.这是一个循序渐进的过程,万事开头难,务必保持耐心,切勿操之过急. 学习编程其实没有什么捷径可走,最好的方法就是反复操练,聆听规则,讨论方法,都不如真正做点什么. 在掌握了一些编程语言的语法语义之后,接下来的难题就是怎样才能写出好的程序.那么,我们首先来看看什么是好的程序.

linux网络编程之shutdown() 与 close()函数详解

linux网络编程之shutdown() 与 close()函数详解 参考TCPIP网络编程和UNP: shutdown函数不能关闭套接字,只能关闭输入和输出流,然后发送EOF,假设套接字为A,那么这个函数会关闭所有和A相关的套接字,包括复制的:而close能直接关闭套接字. 1.close()函数 [cpp] view plain copy print? <span style="font-size:13px;">#include<unistd.h> int