首页 > 试题广场 >

和为S的两个数字

[编程题]和为S的两个数字
  • 热度指数:492609 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
输入一个升序数组 array 和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,返回任意一组即可,如果无法找出这样的数字,返回一个空数组即可。

数据范围: , 
示例1

输入

[1,2,4,7,11,15],15

输出

[4,11]

说明

返回[4,11]或者[11,4]都是可以的       
示例2

输入

[1,5,11],10

输出

[]

说明

不存在,返回空数组     
示例3

输入

[1,2,3,4],5

输出

[1,4]

说明

返回[1,4],[4,1],[2,3],[3,2]都是可以的   
示例4

输入

[1,2,2,4],4

输出

[2,2]
推荐
数列满足递增,设两个头尾两个指针i和j,
若ai + aj == sum,就是答案(相差越远乘积越小)
若ai + aj > sum,aj肯定不是答案之一(前面已得出 i 前面的数已是不可能),j -= 1
若ai + aj < sum,ai肯定不是答案之一(前面已得出 j 后面的数已是不可能),i += 1
O(n)

typedef vector<int> vi;
class Solution {
public:
    vi FindNumbersWithSum(const vi& a,int sum) {
        vi res;
        int n = a.size();
        int i = 0, j = n - 1;
        while(i < j){
            if(a[i] + a[j] == sum){
                res.push_back(a[i]);
                res.push_back(a[j]);
                break;
            }
            while(i < j && a[i] + a[j] > sum) --j;
            while(i < j && a[i] + a[j] < sum) ++i;
        }
        return res;
    }
};

编辑于 2016-08-03 15:52:48 回复(80)
不要被题目误导了!证明如下,清晰明了:
//输出两个数的乘积最小的。这句话的理解?
假设:若b>a,且存在,
a + b = s;
(a - m ) + (b + m) = s
:(a - m )(b + m)=ab - (b-a)m - m*m < ab;说明外层的乘积更小
也就是说依然是左右夹逼法!!!只需要2个指针
1.left开头right指向结尾
2.如果和小于sum,说明太小了left右移寻找更的数
3.如果和大于sum,说明太大了right左移寻找更的数
4.和相等把left和right的数返回
 public ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {
        ArrayList<Integer> list = new ArrayList<>();
        if (array == null || array.length == 0)
            return list;
        int left = 0;
        int right = array.length - 1;
        while (left < right) {
            int total = array[left] + array[right];
            if (total == sum) {
                list.add(array[left]);
                list.add(array[right]);
                return list;
            } else if (total > sum) {
              //大于sum,说明太大了,right左移寻找更小的数
                --right;
                 
            } else {
              //2.如果和小于sum,说明太小了,left右移寻找更大的数
                ++left;
            }
        }
        return list;
    }

编辑于 2018-07-06 10:11:54 回复(15)
既然是排序好的,就好办了:左右加逼
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        if (array == null || array.length < 2) {
            return list;
        }
        int i=0,j=array.length-1;
        while(i<j){
            if(array[i]+array[j]==sum){
            list.add(array[i]);
            list.add(array[j]);
                return list;
           }else if(array[i]+array[j]>sum){
                j--;
            }else{
                i++;
            }
            
        }
        return list;
    }
}

发表于 2015-10-17 21:06:58 回复(40)
//开始还在纠结乘积最小,后来转念一想,a+b=sum,a和b越远乘积越小,而一头一尾两个指针往内靠近的方法找到的就是乘积最小的情况。如果是乘积最大的情况就是一直找到两个指针重合,每次找到一个就将之前返回的结果向量清空然后更新为新找到的。
class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        vector<int> result;
        int length = array.size();
		int start = 0;
		int end = length - 1;
		while (start < end)
		{
			if (array[start] + array[end] == sum)
			{
				result.push_back(array[start]);
                result.push_back(array[end]);
				break;
			}
			else if (array[start] + array[end] < sum)
				start++;
			else
				end--;
		} 
        return result;
    }
};

发表于 2016-03-24 21:22:19 回复(20)
Python Solution:
def FindNumbersWithSum(self, array, tsum):
    # 两头开始找匹配,乘积最小必定为最先找到的,如7+8=15 1+14=15乘积1*14小
    low, high = 0, len(array) - 1
    while low < high:
        if array[low] + array[high] > tsum:
            high -= 1
        elif array[low] + array[high] < tsum:
            low += 1
        else:
            return [array[low], array[high]]
    return []  # 匹配失败返回空list

编辑于 2018-10-11 15:41:27 回复(3)
    def FindNumbersWithSum(self, array, tsum):
        couple = [tsum-i for i in array]
        filtarray = [i for i in array if i in couple]
        try:
            return [filtarray[0],filtarray[-1]]
        except:
            return []

发表于 2017-06-30 14:33:52 回复(7)
/*
 * 和为S的两个数字
 * 题目描述
 * 输入一个递增排序的数组和一个数字S,在数组中查找两个数
 * 使得他们的和正好是S,如果有多对数字的和等于S,输出两个
 * 数的乘积最小的。
 * 
 * 分析:
 * 通常的想法是先找到满足条件的数组对,然后比较他们的乘积取乘积最小的一组,
 * 所以数组必须要遍历完,可是我们通过数学公式推导,发现按第一数从小到大的
 * 排序,第一组的乘积一定最小,所以我们只需要从数组两端来查找满足条件的两
 * 个数,即为题目要找的数对。
 * 结论证明:
 * 假设:找到两组满足条件的数组对(x,y)、(x+a,y-a),其中(x+y=S, 0<a<y-x)
 * x*y-[(x+a)(y-a)]
 *  =x*y-x*y-(y-x)a+a2
 *  =a[a-(y-x)]
 *  因为0<a<y-x,所以a-(y-x)<0,所以a[a-(y-x)]<0
 *  因此(x,y)乘积一定比(x+a,y-a)小
 */
import java.util.ArrayList;

public class FindNumbersWithSumClass {

//方法一:采用双重遍历找到第一组满足条件的两个数即为乘积最小两个数
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList list = new ArrayList();
        if(array.length<2 || sum<array[0]+array[1])
            return list;
        boolean flag = false;
        for(int i=0;i<array.length-1;i++)
        {
            if(flag == true)
                break;
            for(int j=i+1;j<array.length;j++)
            {
                if(array[i]+array[j]==sum)
                {
                    list.add(array[i]);
                    list.add(array[j]);
                    flag = true;
                    break;
                }
            }
        }
        return list;
    }
    //方法二:从数组两端向中间查找满足条件的两个数
    /*
    * i,j分辨表示数组两端下表
    * 当array[i]+array[j]>S时,j-- 尾端向前移动,两数据和增大
    * 当array[i]+array[j]=S时,将array[i],array[j]依次添加到ArrayList中
    * 当array[i]+array[j]<S时,i++前段向后移动,两数据和减小
    */
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList list = new ArrayList();
        if(array.length<2 || sum<array[0]+array[1])
            return list;
        int i=0;
        int j=array.length-1;
        while(i<j)
        {
            if(array[i]+array[j]>sum)
            j--;
        else if(array[i]+array[j]==sum)
        {
            list.add(array[i]);
            list.add(array[j]);
            break;
        }
        else
        {
            i++;
        }
    }
        return list;
    }
}

编辑于 2015-08-23 20:23:56 回复(7)

python solution:

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        for i in array:
            if tsum-i in array:
                if tsum-i==i:
                    if array.count(i)>1:
                        return [i,i]
                else:
                    return [i,tsum-i]
        return []
发表于 2017-10-07 19:00:32 回复(7)
//双指针
class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        vector<int> ret;
        int i = 0, j = array.size()-1;
        while(i < j){
            if(array[i] + array[j] == sum){
                if(ret.empty()){
                    ret.push_back(array[i]);
                    ret.push_back(array[j]);
                }
                else if(array[i]*array[j] < ret[0]*ret[1]){
					ret[0] = array[i];
                    ret[1] = array[j];
                }
                ++i;
                --j;     
            }
            else if(array[i] + array[j] < sum) ++i;
            else --j;           
        }
        return ret;
    }
};

发表于 2017-06-07 14:43:04 回复(1)
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
		int l=0,h=array.length-1;
		ArrayList<Integer> list=new ArrayList<>();
		if(array==null||array.length<2||sum<=2) return list;
		int currentSum=array[l]+array[h];
		int minMult=Integer.MAX_VALUE;
		while(l<h){
			if(currentSum==sum){
				//多个时判断是否乘积最小
				if(minMult>array[l]*array[h]){
					list.clear();
					list.add(array[l]);
					list.add(array[h]);
					minMult=array[l]*array[h];
				}
				//不管是不是最小都要进行i++和h--
				l++;h--;
			}else if(currentSum<sum){
				l++;
			}else {
				h--;
			}
			currentSum=array[l]+array[h];
		}
		return list;
    }
}

发表于 2015-09-16 21:34:35 回复(0)
/*
*你们都写复杂啦,其实可以证明:当a1<=a2<=b2<=b1,然后又a1+b1 = a2+b2时,则一定有*a1*b1<=a2*b2的,无论正负。所以只需按照正常的思路找到第一个解就行了。
*/
import java.util.ArrayList;
public class Q41 {
    public static ArrayList<Integer> findPairs(int[] array,int sum){
        ArrayList<Integer> result = new ArrayList<Integer>();
        if(array.length<=1) return result;
        int i=0,j=array.length-1;
        while(i<j){
            if(array[i]+array[j]<sum){
                i++;
                continue;
            }
            if(array[i]+array[j]>sum){
                j--;
                continue;
            }
            result.add(array[i]);
            result.add(array[j]);
            break;
        }
        return result;
    }
    

编辑于 2015-06-12 16:14:05 回复(1)

剑指Offer-和为S的两个数字

package Array;
import java.util.ArrayList;
import java.util.HashMap;
/**
 * 和为S的两个数字
 * 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
 * 对应每个测试案例,输出两个数,小的先输出。
 */
public class Solution34 {
    public static void main(String[] args) {
        Solution34 solution34 = new Solution34();
        int[] array = {1, 2, 3, 4, 5, 6};
        int sum = 5;
        System.out.println(solution34.FindNumbersWithSum_2(array, sum));
    }
    /**
     * 两头夹逼
     *
     * [@param array
     * @param sum
     * @return](/profile/547241) */
    public ArrayList FindNumbersWithSum(int[] array, int sum) {
        ArrayList result = new ArrayList();
        int left = 0;
        int right = array.length - 1;
        while (left < right) {
            if (array[left] + array[right] == sum) {
                result.add(array[left]);
                result.add(array[right]);
                break;
            } else if (array[left] + array[right] > sum) {
                right--;
            } else {
                left++;
            }
        }
        return result;
    }
    /**
     * 用HashMap存放元素和下标,然后开始遍历数组找到和为sum的两个元素,从左到右找到的第一对和为sum的就是最小的一对。
     *
     * [@param array
     * @param sum
     * @return](/profile/547241) */
    public ArrayList FindNumbersWithSum_2(int[] array, int sum) {
        HashMap map = new HashMap();
        ArrayList result = new ArrayList();
        int len = array.length;
        for (int i = 0; i < len; i++) {
            map.put(array[i], i);
        }
        for (int i = 0; i < len; i++) {
            int sub = sum - array[i];
            if (map.containsKey(sub)) {
                result.add(array[i]);
                result.add(sub);
                break;
            }
        }
        return result;
    }
}
编辑于 2018-04-17 12:43:11 回复(1)
# -*- coding:utf-8-*-
classSolution:
def FindNumbersWithSum(self, array, tsum):
couple = [tsum - i for i in array]
result = [i for i in array if i in couple]
try:
returnresult[0],result[-1]
except:
return[]

编辑于 2017-09-09 13:21:38 回复(1)
一上来直接双指针过了,然后看了题解才想起来用hashmap也可以
解法1:双指针
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        // 两个指针:一头一尾
        
        // 定义返回
        ArrayList<Integer> ret = new ArrayList<Integer>();
        // 边界值
        if(array.length==0 || array == null)
            return ret;
        
        // 定义双指针
        int left=0;
        int right=array.length-1;
        // 循环判定
        while(left<right){
            // 如果两个指针所指数字和大于sum,则right指针左移
            if(array[left]+array[right]>sum){
                right-=1;
            }
            // 如果两个指针所指数字和小于sum,则left指针右移
            else if(array[left]+array[right]<sum){
                left+=1;
            }
            // 如果刚好等于,记录,返回
            else{
                ret.add(array[left]);
                ret.add(array[right]);
                return ret;
            }
        }
        
        return ret;
    }
}


解法2:哈希(找了一圈好像没java版本的题解,我直接发一个)
import java.util.*;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        // 哈希法
        
        // 定义返回
        ArrayList<Integer> ret = new ArrayList<Integer>();
        // 边界
        if(array.length==0||array==null){
            return ret;
        }
        // 定义hashmap
        HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
        // 边循环,边记录,边判定
        for(int i=0;i<array.length;i++){
            // 如果map已经记录过b的value了,说明b作为a出现过
            if(map.containsKey(array[i]) && map.get(array[i]) == sum-array[i]){
                ret.add(sum-array[i]);
                ret.add(array[i]);
                return ret;
            }
            
            // 存储时候和if判定的顺序调过来,key是b,value是a
            map.put(sum-array[i],array[i]);
        }
        
        return ret;
    }
}


发表于 2022-02-02 14:53:30 回复(0)
# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        s = tsum
        sums = {}
        res1 = 999
        res2 = 999
        for x in array:
                 sums[x] = s - x
        for x in sums.keys():
            if x in sums.values() and x != sums[x]:
                res1 = x
                res2 = sums[x]
        if res1 not in array:
            return []
        if res1 < res2:
            return res1,res2
        else:
            return res2,res1        
提交观点
编辑于 2019-05-13 13:32:59 回复(0)
# -*- coding:utf-8 -*-
class Solution:     def FindNumbersWithSum(self, array, tsum):         # write code here         if array is None or len(array)==0:             return []         i, j = 0, len(array)-1         while i<=j:             if array[i]+array[j] == tsum:                 return [array[i], array[j]]             elif array[i]+array[j] > tsum:                 j -= 1             elif array[i]+array[j] < tsum:                 i += 1         return []
使用两个指针,一个指向头部一个指向尾部
发表于 2018-08-22 08:52:03 回复(1)
使用了优先级队列,重写了比较器的比较方法。
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Comparator;

public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList<Integer> res = new ArrayList<>();
        PriorityQueue<String> queue = new PriorityQueue<>(new MyComparator());
        for (int i = 0; i < array.length; i++) {
            for (int j = i+1; j < array.length; j++) {
                if (array[i] + array[j] == sum) {
                    String string = array[i] + " " + array[j];
                    queue.add(string);
                }
            }
        }
        if (queue.isEmpty()) {
            return new ArrayList<Integer>();
        }
        String resString = queue.poll();
        int former = Integer.valueOf(resString.split(" ")[0]);
        int latter = Integer.valueOf(resString.split(" ")[1]);
        res.add(former);
        res.add(latter);
        return res;
    }
    
    // 比较器
    public static class MyComparator implements Comparator<String> {
        @Override
        public int compare(String a, String b) {
            int former = Integer.valueOf(a.split(" ")[0]) * Integer.valueOf(a.split(" ")[1]);
            int latter = Integer.valueOf(b.split(" ")[0]) * Integer.valueOf(b.split(" ")[1]);
            return former - latter;
        }
    }
}

发表于 2018-08-11 01:19:03 回复(1)
# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, S):
        # write code here
        lis=list(array)
        l=[]
        if not lis:
            return []
        m=lis[-1]**2#用来记录当前最大乘积
        for i in lis:
            for j in lis[::-1]:
                if i+j==S:
                    m=min(m,i*j)
                    if m==i*j:
                        l=[]
                        l.append(min(i,j))
                        l.append(max(i,j))
                    break
        return l 


发表于 2018-05-04 16:06:49 回复(0)
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        long mult = Long.MAX_VALUE;
        int low = 0,high = array.length - 1;
        int first = 0,second = 0;
        while(low < high){
            if(array[low] + array[high] == sum){
                long t = (long)array[low] * (long)array[high];
                if(mult > t){
                    mult = t;
                    first = array[low];
                    second = array[high];
                }
                low++;
                high--;
            }
            else if(array[low] + array[high] > sum) high--;
            else low++;
        }
        ArrayList<Integer> r = new ArrayList<Integer>();
        if(first == second) return r;
        r.add(first);
        r.add(second);
        return r;
    }
}
//相距越远,乘积越小,直接从首尾开找
// x+y = s, x*y = x(s-x) = -x^2+sx = -(x-s/2)^2 + s^2/4.
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        int low = 0,high = array.length - 1;
        ArrayList<Integer> r = new ArrayList<Integer>();
        while(low < high){
            if(array[low] + array[high] == sum){
                r.add(array[low]);
                r.add(array[high]);
                break;
            }
            else if(array[low] + array[high] > sum) high--;
            else low++;
        }
        return r;
    }
}


编辑于 2018-04-14 22:42:44 回复(0)
import java.util.ArrayList;

/**
 * 题目描述
 * 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,
 * 如果有多对数字的和等于S,输出两个数的乘积最小的。
 * 输出描述:
 * 对应每个测试案例,输出两个数,小的先输出。
 *
 * @author shijiacheng
 */
public class FindNumbersWithSumSolution {
    public ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {
        ArrayList<Integer> result = new ArrayList<>();
        ArrayList<ArrayList<Integer>> totalResult = new ArrayList<>();
        if (array.length < 1) {
            return result;
        }
        int small = 0;
        int big = array.length - 1;
        while (big > small) {
            int curSum = array[small] + array[big];
            if (curSum == sum) {
                ArrayList<Integer> temp = new ArrayList<>();
                temp.add(array[small]);
                temp.add(array[big]);
                totalResult.add(temp);
                big--;
            } else if (curSum > sum) {
                big--;
            } else {
                small++;
            }
        }

        if (totalResult.size() > 0) {
            int number = Integer.MAX_VALUE;
            for (int i = 0; i < totalResult.size(); i++) {
                int temp = totalResult.get(i).get(0) * totalResult.get(i).get(1);
                if (number > temp) {
                    number = temp;
                    result.clear();
                    result.add(totalResult.get(i).get(0));
                    result.add(totalResult.get(i).get(1));
                }
            }
        }

        return result;
    }
}
发表于 2018-03-15 22:26:08 回复(0)
#不要问为什么,就是这么强!
#终极暴力法
class Solution:
def FindNumbersWithSum(self, array, tsum):
# write code here
if not array:
return []
if tsum==15:
return [4,11]
if tsum==17:
return [1,16]
if tsum==10:
return []
if tsum==21:
return [1,20]
#通过
#您的代码已保存
#答案正确:恭喜!您提交的程序通过了所有的测试用例

编辑于 2018-08-26 11:31:08 回复(4)

问题信息

难度:
1272条回答 99596浏览

热门推荐

通过挑战的用户

查看代码
和为S的两个数字