花费最大金额-数组

题目:双十一众多商品进行打折销售,小明想购买自己心仪的一些物品,但由于受购买资金限制,所以他决定从众多心仪商品中购买三件,而且想尽可能的花完资金,现在请你设计一个程序帮助小明计算尽可能花费的最大资金数额。

输入描述

输入第一行为一维整型数组M,数组长度小于100,数组元素记录单个商品的价格,单个商品价格小于1000。
输入第二行为购买资金的额度R,R小于100000。

输出描述

输出为满足上述条件的最大花费额度。
注意:如果不存在满足上述条件的商品,请返回-1。

示例

输入:
23,26,36,27
78
输出:
76
说明:
金额23、26和27相加得到76,而且最接近且小于输入金额78
输入:
23,20,40
26
输出:
-1
说明:
因为输入的商品,无法组合出来满足三件之和小于26.故返回-1

`

public class 最大花费金额 {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        String[] strings = sc.nextLine().split(",");
        int[] arr = Arrays.stream(strings).mapToInt(Integer::parseInt).toArray();
        int limit = sc.nextInt();
        Arrays.sort(arr);
        //处理并排序
        //格式正确,无需考虑小于3个的情况
        int result = -1;
        //计算,双指针,固定左边两个数,遍历下一个数
        for (int i = 0; i < arr.length - 2; i++) {
            for (int j = i + 2; j < arr.length; j++) {
                int curResult = arr[i] + arr[i + 1] + arr[j];
                if (curResult > limit) {
            //因为排好序了,所以如果已经超出,则继续外层循环
                    break;
                } else {
                    result = Math.max(curResult, result);
                }
            }
        }
        System.out.println(result);
    }
}

`
思路与算法

题目要求找到与目标值target 最接近的三元组,这里的「最接近」即为差值的绝对值最小。我们可以考虑直接使用三重循环枚举三元组,找出与目标值最接近的作为答案,时间复杂度为 O(N3)。然而本题的N最大为1000,会超出时间限制。

那么如何进行优化呢?我们首先考虑枚举第一个元素 a,对于剩下的两个元素 b 和 c,我们希望它们的和最接近target−a。对于 b 和 c,如果它们在原数组中枚举的范围(既包括下标的范围,也包括元素值的范围)没有任何规律可言,那么我们还是只能使用两重循环来枚举所有的可能情况。因此,我们可以考虑对整个数组进行升序排序,这样一来:

假设数组的长度为 n,我们先枚举 a,它在数组中的位置为 i;

为了防止重复枚举,我们在位置[i+1,n) 的范围内枚举 b 和 c。

当我们知道了 b 和 c 可以枚举的下标范围,并且知道这一范围对应的数组元素是有序(升序)的,那么我们是否可以对枚举的过程进行优化呢?

答案是可以的。借助双指针,我们就可以对枚举的过程进行优化。我们用 pb和 pc分别表示指向 b 和 c 的指针,初始时,pb指向位置 i+1,即左边界;pc指向位置 n−1,即右边界。在每一步枚举的过程中,我们用 a+b+c 来更新答案,并且:

如果 a+b+c≥target,那么就将 pc向左移动一个位置;

如果 a+b+c<target,那么就将 pb向右移动一个位置。

这是为什么呢?我们对 a+b+c≥target的情况进行一个详细的分析:

如果 a+b+c≥target,并且我们知道 pb到 pc这个范围内的所有数是按照升序排序的,那么如果 pc不变而 pb向右移动,那么 a+b+c的值就会不断地增加,显然就不会成为最接近 target\的值了。因此,我们可以知道在固定了 pc的情况下,此时的 pb就可以得到一个最接近 target的值,那么我们以后就不用再考虑 pc了,就可以将 pc向左移动一个位置。

同样地,在 a+b+c<target时:如果 a+b+c<target并且我们知道 pb到 pc这个范围内的所有数是按照升序排序的,那么如果 pb不变而 pc向左移动,那么 a+b+c的值就会不断地减小,显然就不会成为最接近 target的值了。因此,我们可以知道在固定了 pb的情况下,此时的 pc就可以得到一个最接近 target的值,那么我们以后就不用再考虑 pb了,就可以将 pb向右移动一个位置。实际上,pb和 pc就表示了我们当前可以选择的数的范围,而每一次枚举的过程中,我们尝试边界上的两个元素,根据它们与 target的值的关系,选择「抛弃」左边界的元素还是右边界的元素,从而减少了枚举的范围。
小优化
本题也有一些可以减少运行时间(但不会减少时间复杂度)的小优化。当我们枚举到恰好等于 target的 a+b+c时,可以直接返回 target作为答案,因为不会有再比这个更接近的值了。
当我们枚举 a,b,c中任意元素并移动指针时,可以直接将其移动到下一个与这次枚举到的不相同的元素,减少枚举的次数。

作者:力扣官方题解
链接:https://leetcode.cn/problems/3sum-closest/solutions/301382/zui-jie-jin-de-san-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

posted @ 2023-11-02 12:20  约拿小叶  阅读(32)  评论(0编辑  收藏  举报