在递增排序的数组中,找到和为指定值的两个元素

import com.google.common.base.Preconditions;

import java.util.Arrays;

/**
 * 在递增排序的数组中,找到和为指定值的两个元素。若存在多对这样的元素,则找到任意一对即可。
 *
 * 输入一个正数sum,打印出所有和为sum的连续正数序列(序列中最少2个数字)。
 */
public class GetNumbersWithSumInArray {

    /**
     * 在递增排序的数组中,找到和为指定值的两个元素。若存在多对这样的元素,则找到任意一对即可。
     *
     * 思路:
     *  1)定义两个指针:第一个指针small指向数组的第一个元素(即最小元素),第二个指针big指向数组的最后一个元素(即最大元素)。
     *  2)若两个指针指向的元素的和currentSum大于指定的和sum,则big指针向前移动(目的是为了减小currentSum的值),
     *  3)若两个指针指向的元素的和currentSum小于指定的和sum,则small指针向后移动(目的是为了增加currentSum的值),
     *  4)若两个指针指向的元素的和currentSum等于指定的和sum,则返回。
     *
     * 时间复杂度O(n)
     *
     * @param array     递增排序的数组
     * @param sum       指定的和
     * @return
     */
    public static int[] getNumbersWithSum(int[] array, int sum) {

        Preconditions.checkArgument(null != array && array.length >= 2);

        int[] result = null;

        int smallIndex = 0;
        int bigIndex = array.length - 1;

        while (smallIndex < bigIndex) {

            int currentSum = array[smallIndex] + array[bigIndex];
            if (currentSum == sum) {
                result = new int[2];
                result[0] = array[smallIndex];
                result[1] = array[bigIndex];
                break;
            } else if (currentSum < sum) {
                smallIndex++;
            } else {
                bigIndex--;
            }
        }
        return result;
    }


    /**
     * 输入一个正数sum,打印出所有和为sum的连续正数序列(序列中最少2个数字)。
     *
     * 思路:
     *  1)定义两个指针:第一个指针small指向序列的第一个元素(即最小元素),第二个指针big指向序列的最后一个元素(即最大元素)。
     *  2)small默认指向1,big默认指向2。
     *  3)若序列的和(small~big之间的数的和)大于sum,则将序列中的最小值去掉,即small向后移动,一直移动到序列的和不大于sum。
     *  4)若序列的和(small~big之间的数的和)小于sum,则将序列中的最大值增大,即big向后移动,一直移动到序列的和不小于sum。
     *  5)若序列的和(small~big之间的数的和)等于sum,则将序列打印出来,然后将big向后移动,继续寻找其它和为sum的序列。(big向后移动后,序列的和就大于sum了,故此时又进入到第3步)
     *  6)序列中最少有两个数字且和为sum,故序列的第一个元素一定小于(sum+1)/2,所以当small不小于(sum+1)/2时,所有和为sum的序列都已经被打印过了。
     *
     * @param sum
     */
    public static void printContinuousNumbersWithSum(int sum) {

        if (sum < 3) return;

        int small = 1;
        int big = 2;

        // 序列中最少有两个数字且和为sum,故序列的第一个元素一定小于(sum+1)/2
        int half = (sum + 1) / 2;

        int currentSum = small + big;

        while (small < half) {

            if (currentSum == sum) {
                printContinuousNumbers(small, big);
            } else {
                // currentSum > sum     将small向后移动,直到currentSum不大于sum
                while (currentSum > sum && small < half) {
                    currentSum = currentSum - small;
                    small++;
                    if (currentSum == sum) printContinuousNumbers(small, big);
                }

            }

            /**
             * 两种情况会执行下面代码:
             *  1)currentSum < sum  将big向后移动,直到currentSum不小于sum
             *  2)currentSum == sum 且 已经将序列打印了,故big继续向后移动,继续寻找和为sum的序列。
             */
            big++;
            currentSum = currentSum + big;
        }
    }

    public static void printContinuousNumbers(int start, int end) {

        for (int i = start; i <= end ;i++) {
            System.out.print(i);
        }
        System.out.println();
    }


    public static void main(String[] args) {

//        int[] array = {1, 2, 4, 7, 11, 15};
//        int[] numbers = getNumbersWithSum(array, 15);
//        System.out.println(Arrays.toString(numbers));

        printContinuousNumbersWithSum(15);

    }

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值