编程题:和为S的两个数

题目:

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输入示例:

[1, 3, 4, 5, 6, 9], 8

输出示例:

[3, 5]

规定:

①需要注意如果有多对数字的和等于S,那么输出两个数的乘积最小的。
②对应每个测试案例,输出两个数,小的先输出。

解题思路:

思路:读题,注意数组是递增排序,很容易想到的就是二分查找和头尾双指针的解法。初步估计解决该问题时,二分查找时间复杂度是O(NlogN),头尾双指针法是O(N)。
注:O(NlogN)是因为此处的二分查找需要对每个元素进行,判断某元素与数组其他元素之和是否为目标值,即N * logN。

(1)二分查找方法

对于数组的每一个元素,挑出来,然后在剩下的所有元素中做二分查找,找到是否有数与之和为目标值。如果有则试图存进结果数组,另外如果结果数组中有值还需要对乘积大小进行判断,将小乘积的两个数放进去。
(注:可能第一时间想到这种方法,方法其实比较笨,时间复杂度O(NlogN)比较高,不推荐,但是可以作为引子,给自己面试时留优化的空间。)

class Solution {
public:
    void swap(vector<int>&array, int i, int j){
        //交换数组元素的函数
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    
    int binary_search(vector<int>&array, int low, int high, int diff){
        //二分搜索
        if(diff<array[low]||diff>array[high]){
            return -1;
        }
        auto mid = (low+high)/2;//auto自动数据类型推导
        if(diff<array[mid]){
            return binary_search(array,low,mid-1,diff);
        }
        else if(diff>array[mid]){
            return binary_search(array,mid+1,high,diff);
        }
        else{
            return mid;
        }
    }
    
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        //复杂度O(NlogN)
        vector<int> result;
        int length = array.size();//长度
        if(length<=1)
            return result;
        for(int low=0;low<length;low++){
            swap(array, low, 0);
            int index = binary_search(array,1,length-1,sum-array[0]);
            if(index!=-1){
                if(result.empty()){
                    result.push_back(array[0]);//注意此处由于swap后锁定数的下标是0
                    result.push_back(array[index]);
                }
                else{
                    int last1=result.front();
                    int last2=result.back();
                    if(array[0]*array[index]<last1*last2){
                        result.clear();
                        result.push_back(array[0]);
                        result.push_back(array[index]);
                    }
                }
            }
            swap(array, low, 0);
        }
        return result;
    }
};

(2)头尾双指针方法

对于有序数组,考虑用头尾双指针遍历法解决,头指针从头部向后,尾指针从尾部向前。其中如果两指针指向元素和等于目标值,则试图存进结果数组。如果大于目标值,则尾指针减小。如果小于目标值,则头指针增加。例如[1,2,4,6,9],8,最开始有1+9>8,说明需要将尾指针减小,减小后1+6<8,说明需要将头指针增大,增大后2+6=8,则将26存进结果数组。另外注意如果结果数组中有值还需要对乘积大小进行判断,将小乘积的两个数放进去。

class Solution {
public:
    int sum_equal(vector<int>&array, int low, int high, int sum){
        //比对两个指针指向的元素和是否等于sum
        if(sum<array[low]){
            return -1;
        }
        int dsum = array[low]+array[high];//两数之和
        if(dsum==sum){
            return 1;
        }
        else if(dsum<sum){//如果相加值比目标数小
            return 0;//增大low
        }
        else{//如果相加值比目标数大
            return 2;//减小high
        }
    }
    
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        //复杂度O(N)
        vector<int> result;
        int length = array.size();//长度
        if(length<=1)
            return result;
        for(int low=0,high=length-1;low<high;){
            int return_flag = sum_equal(array,low,high,sum);
            if(return_flag==-1){
                return result;
            }
            if(return_flag==1){
                if(result.empty()){
                    result.push_back(array[low]);
                    result.push_back(array[high]);
                }
                else{
                    int last1=result.front();
                    int last2=result.back();
                    if(array[low]*array[high]<last1*last2){
                        result.clear();
                        result.push_back(array[low]);
                        result.push_back(array[high]);
                    }
                }
                low++;
                high--;
            }
            else if(return_flag==0){
                low++;
            }
            else{
                high--;
            }
        }
        return result;
    }
};

输入输出测试:

测试用例1:#只有一个组合满足
输入:
[1, 2, 5, 6, 8], 8

输出:
[2, 6]

测试用例2:#有多个组合满足,输出乘积最小的
输入:
[1, 2, 5, 6, 7], 8

输出:
[1, 7]

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracelessLe

❀点个赞加个关注再走吧❀

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值