和为S的两个数字 & 和为S的连续正数序列

一. 和为S的两个数字

题目:

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

解题思路:

1.定义两个指针,分别指向第一个数字和最后一个数字;
2.如果两个指针所指向的数的和等于S, 如果这两个数的乘积小于之前找到的结果就替换掉旧的结果;
3.如果两个指针所指向的数的和大于S,则第二个指针减减;
4.如果两个指针所指向的数的和小于S,则第一个指针加加;

java实现:

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        int minVal = Integer.MAX_VALUE;
        int num1 = Integer.MIN_VALUE;
        int num2 = Integer.MAX_VALUE;
        int i = 0, j = array.length - 1;
        while(i < j){
            if(array[i] + array[j] == sum){
                if(array[i] * array[j] < minVal){
                    minVal = Math.min(minVal, array[i] * array[j]);
                    num1 = array[i];
                    num2 = array[j];
                }
                i++;
                j--;
            }else if(array[i] + array[j] < sum){
                i ++;
            }else{
                j --;
            }
        }
        if(num1 + num2 == sum){
            res.add(num1);
            res.add(num2);
        }
        return res;
    }
}

二. 和为S的连续正数序列

题目:

输入一个正数s,打印出所有和为s的连续整数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8。
注:美团暑期实习1面问到了这个题

解题思路:

解法一:数学解法

解题思路:

设有a个连续的正整数,从b(b>0)开始,和为S。
b + b + 1 + b + 2 + … + b + a -1 = S
ab + a(a-1)/2 = S
a(2b + a - 1) = 2S
因为a,b属于整数,所以2S能整除a
所以枚举2S的约数记为a,时间复杂度 O(S) ,b=1/2(2N/a+1-a),判断b是否属于整数,时间复杂度 O(1)

java实现:
import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
        for(int a = 2; a * a < 2 * sum; a ++){ //有a个连续的整数
            if(2*sum % a == 0){//a是2*sum的约数
                if((2*sum + a - a*a) / (2 * a) > 0 && (2*sum + a - a*a) % (2 * a) == 0){
                    ArrayList<Integer> al = new ArrayList<Integer>();
                    for(int i = (2*sum + a - a*a) / (2 * a); i < ((2*sum + a - a*a) / (2 * a) + a); i ++){
                        al.add(i);
                    }
                    res.add(0, al);
                }
            }
        }   
        return res;
    }
}

解法二:

解题思路:

1.用两个整数small和big分别表示序列的最小值和最大值,small初始化为1,big初始化为2。
2.如果从small到big的和大于s,从序列中去掉最小值,即增大small的值。
3.如果从small到big的和小于s,增大big,让这个序列包含更多的数字,因为至少含有两个数字。
4.如果从small到big的和等于s,打印,之后增大big。
5.small增加到(1+sum)/ 2为止。

本题技巧:

通常我们用循环求一个连续序列的和,但考虑到每一次操作之后的序列和操作之前的序列相比大部分数字都是一样的,只是增加或者减少了一个数字,因此,本题在前一个序列的和的基础上求操作之后的序列的和。减少了不必要的运算,提高了代码的效率。

java实现:
import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
        int small = 1, big = 2;
        int curSum = small + big;
        while(small < ((sum + 1) / 2)){
            if(curSum <= sum){
                if(curSum == sum){
                    ArrayList<Integer> list = new ArrayList<Integer>();
                    int i = small;
                    while(i <= big){
                        list.add(i);
                        i ++;
                    }
                    res.add(list);
                }
                big ++;
                curSum += big;
            } else {
                curSum -= small;
                small ++;
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值