编程题:和为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]

编程题:和为S的两个数_第1张图片

你可能感兴趣的:(#,编程题,数据结构,算法,剑指offer,数组)