和为S的两个数字

题目描述

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

输出描述:

对应每个测试案例,输出两个数,小的先输出。

       在写解法之前,先思考一个问题,在存在多组和S的情况下,满足什么条件,输出两个数的乘积最小,结论是:在数组中,两个数字离的越远,其乘积就越小。

        证明:在存在多组和为S的情况,我们可以做如下假设

x+y=S(S是个常数)

y>x

  令y=x+d

=>x+(x+d)=S,

=>x=(S-d)/2

最后推出的x * y的结果为:

   x * y = x * (x + d) = (S^2 - d^2) / 4

故当d越大时,其乘积就会越小,所以顺序遍历,遇到的第一组即是我们所要找的结果。

解法一:

      顺序遍历数组,令second_num = S - array[i],然后利用二分搜索法(利用泛型算法find也可以),查找second_num是否在数组中。如果在,array[i] 和 second_sum就是最终结果。如果不在,不存在满足条件的数对。

class Solution {
public:
	std::vector<int> FindNumbersWithSum(std::vector<int> array, int sum) {
		std::vector<int> vec;

		if (array.size() <= 1 || array.back() * 2 <= sum || array.front() * 2 >= sum)
			return vec;

		int first_num, second_num;
		int length = array.size() - 1;
		int index;
		for (int index = 0; index <= length; index++)
		{
			first_num = array[index];
			second_num = sum - first_num;

			if (first_num >= second_num)
				break;

			int i = binarySearch(array, index, length, second_num);
			if (i != -1)
			{	
			    vec.push_back(first_num);
			    vec.push_back(second_num);
                return vec;
			}
		}
		return vec;
	}
private:
	int binarySearch(std::vector<int> &array, int start, int end, int key_value)
	{
		int mid = start + (end - start) / 2;

		while (start <= end)
		{
			if (array[mid] < key_value)
			{
				start = mid + 1;
			}
			else if (array[mid] > key_value)
			{
				end = mid - 1;
			}
			else
			{
				return mid;
			}
			mid = start + (end - start) / 2;
		}

		return -1;
	}
};

解法二:

      双指针法,设头尾两个指针 i 和 j

  • 如果 i + j == S, 这就是答案;
  • 如果 i + j > S, 那么 j 肯定不是我们要找的答案(已经得出 i 前边的数是不可能的), j--;
  • 如果 i + j < S, 那么 i 肯定不是我们要找的答案(已经得出 j 后边的数是不可能的), i--;

仅需一次遍历,算法复杂度O(n)

class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        vector<int> vec;
        
        if (array.size() <= 1 || array.back() * 2 <= sum || array.front() * 2 >= sum)
            return vec;
        
        int i = 0, j = array.size() - 1;
        
        while (i < j)
        {
            if (array[i] + array[j] == sum)
            {
                vec.push_back(array[i]);
                vec.push_back(array[j]);
                return vec;
            }
            while (i < j && array[i] + array[j] > sum) j--;
            while (i < j && array[i] + array[j] < sum) i++;
        }
        
        return vec;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值