Java篇—和为S的两个数字

在递增排序数组中,通过双指针法寻找和为S的两个数字,使得它们的乘积最小。从数组首尾开始,如果两数之和大于S则减小较大数,反之增加较小数,直至找到满足条件的数对。
摘要由CSDN通过智能技术生成

题目描述:

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

思路分析:

由于是递增排序的数组,所以,我们可以使用两个指针,分别指向数组的首元素和尾元素(一个从前往后,指向较小的数,一个从后往前,指向较大的数),这样找到的两个数的乘积必然是最小的。当两个数的和大于S时,较大的数字指针向左移动,当两个数的和小于S时,较小的数字指针向右移动,当两个指针相遇时,查找结束。

代码实现:

import java.util.ArrayList;
public class Exercise20 {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,6,8,9,12};
        System.out.println(findNumbersWithSum(array,12));   //输出结果  [3,9]
    }

    private static ArrayList<Integer> findNumbersWithSum(int[] array, int sum) {
        ArrayList<Integer> list = new ArrayList<>();
        //如果原数组的长度小于2或者原数组为空,直接返回list
        if(array.length < 2 || array == null){
            return list;
        }
        //定义两个指针,分别指向数组的首元素和尾元素
        int low = 0;
        int high = array.length - 1;
        //对数组进行遍历,当首尾指针相遇时结束,即low = high
        //让两个数字的位置不断靠近
        while(low < high){
            if((array[low] + array[high] > sum)){
                //如果首尾元素的和大于sum,则尾指针减一,即 high--
                high--;
            }else if((array[low] + array[high] < sum)){
                //如果首尾元素的和小于sum,则首指针加一,即 low++
                low++;
            }else{
                //如果首尾元素的和等于sum,则把首尾元素加入到list集合中,最后返回即可
                list.add(array[low]);
                list.add(array[high]);
                return list;
            }
        }
        return list;
    }
}

解法2代码实现及详细注释:

import java.util.ArrayList;
public class Exercise20 {
    public static void main(String[] args) {
        int[] array = {-2,-1,0,1,3,4};
        System.out.println(findNumbersWithSum1(array,1));   //输出结果  [-2,3]
    }

    private static ArrayList<Integer> findNumbersWithSum1(int[] array, int sum) {
        ArrayList<Integer> list = new ArrayList<>();
        //如果原数组的长度小于2或者原数组为空,直接返回list
        if(array.length < 2 || array == null){
            return list;
        }

        /**
         * 定义两个指针和i和j分别指向数组的第一个元素和第二个元素;
         * 外层循环控制第一个元素的位置,内层循环控制第二个元素的位置;
         * 如果 array[i] + array[j] = sum 并且list为空,代表其是第一次放入,
         *           将p1和p2对应的值添加到list集合中,并且保存乘积max;
         * 如果 array[i] + array[j] = sum 并且list集合不为空,代表其不是第一次放入,
         *       比较当前的两个值和之前存入的两个值乘积的大小,
         *       如果当前乘积小于之前保存的乘积,则重新创建一个list对象
         *       保存当前的两个值,并使max = 当前两个值的乘积
         * 最后返回list集合即可。
         */
        //max用来保存最大的乘积
        int max = 0;
        //i的取值范围为[0,array.length - 2],i不能指向数组的最后一个元素
        for (int i = 0; i < array.length - 1; i++) {
            //j的取值范围为[1,array.length - 1],j不能指向数组的第一个元素
            for (int j = 1; j < array.length; j++) {
                //如果两者相加等于sum,并且list为空,那么代表其是第一次放入
                if((array[i] + array[j]) == sum && list.size() == 0){
                    list.add(array[i]);
                    list.add(array[j]);
                    //保存当前两者的乘积
                    max = array[i] * array[j];
                }
                //如果两者相加等于sum,并且list不为空,那么代表其不是第一次放入
                if((array[i] + array[j]) == sum && list.size() != 0){
                    //比较当前两个数的乘积与第一次放入的两个数乘积的大小
                    if((array[i] * array[j]) < max){
                        /**
                         * 如果当前i和j指针指向的两个数的乘积小于max,重新new ArrayList一个对象
                         * 将其放入到list集合中,保存最大值即可
                         */
                        list = new ArrayList<>();
                        list.add(array[i]);
                        list.add(array[j]);
                        //保存当前两者的乘积
                        max = array[i] * array[j];
                    }
                }
            }
        }
        return list;
    }
}

题目总结:

前者解法较为灵活,巧妙的抓住了两个数乘积最小的条件,定义首尾指针遍历时第一次找到的两个数即为所求数。

例:[1,2,3,4]  sum = 5 ,1*4肯定小于2*3。

后者解法较为复杂,但易于理解,把第一对元素之和等于sum的两个数的乘积保存下来,与后面出现的每一对元素之和等于sum的两个数的乘积作比较,将较小乘积的那两个数放入到list集合中即可。

心灵鸡汤:大脑的知识储备从来不是空穴来风,既然不是天才,为何不去努力?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值