【每日一题】LeetCode. 1300. 转变数组后最接近目标值的数组和

每日一题,防止痴呆 = =

一、题目大意

给你一个整数数组 arr 和一个目标值 target ,请你返回一个整数 value ,使得将数组中所有大于 value 的值变成 value 后,数组的和最接近 target (最接近表示两者之差的绝对值最小)。

如果有多种使得和最接近 target 的方案,请你返回这些整数中的最小值。

请注意,答案不一定是 arr 中的数字。
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-mutated-array-closest-to-target

二、题目思路以及AC代码

思路一

这个思路我觉得是比较容易想到的一个,首先排序是肯定的,因为很明显这道题要利用数组元素的大小关系。然后其实题目要你求value,就是让你在排序好的数组中切一刀,这刀后的元素都变为value,求这一刀切在哪,会使变换后数组的和最接近target。

我先描述思路,直接用一个例子说明。
[3, 5, 9], target = 12

首先,对数组排序,因为原本就是有序的,所以排序后数组不变,还是[3, 5, 9];

然后我们计算 12 / 3 = 4 > 3,所以这一刀不会切在3前面。

然后我们再计算 (12 - 3) / 2 = 4.5 < 5,所以这一刀就切在 3 和 5 之间。

由于4.5 - 4 <= 0.5,所以结果是4。

下面对上述的例子进行解释,首先我们 12 / 3,是计算如果这一刀切在3前面,那么需要value值为多少,才能得到target,答案是4,那么比3还大,所以矛盾,这一刀不能切在这。然后,我们计算(12 - 3) / 2,是假设如果这一刀切在3 和 5 之间,那么需要的value是4.5,正好满足要求,但是题目又要求value是整数,其实4.5对于取4和取5是一样的,题目要求去最小所以就取4了,如果是4 ~ 4.5,那么就该取4,如果是4.6 ~ 5,就该取5,因为如果不是4.5的话,就会涉及到差距大小的问题了。

可能有人会疑惑,为什么我假设刀切在某个地方,如果求得的value值大于右边,就不可能。这还利用了数组和是随value值得增加而增加的,如果求得的value值大于右边,那么就只能说明你如果在这切,得到的数组和一定小于target,那么你再尝试向右切,一定能得到更好的结果。

思路二

这个就是和我自己想的截然不同的思路了。基本思路是枚举可能的value值,然后对二分找到该value值得位置,然后对数组求和,记录最接近的时候取得的value值,对数组求和自然利用了前缀和,来降低复杂度。

思路三

这个是思路二的一个拓展。既然你可以在找value值位置的时候使用二分,那么在枚举value值的时候也可以考虑使用二分,但由于最接近target的有两个方向,所以要分别对这两个方向进行两次二分求解,然后再比较这两次的结果哪一个更接近。

AC代码

因为我自己的思路和官解还是差挺多的,所以我就只实现了自己的思路,官解的只是看了一下,拓展一下思路而已。

class Solution {
public:
    int getInt(double x) {
        int ix = x;

        if (x - ix > 0.5) return ix + 1;
        return ix;
    }

    int findBestValue(vector<int>& arr, int target) {
        int n_size = arr.size();

        sort(arr.begin(), arr.end());

        double first = (double)target / n_size;
        if (first < arr[0]) return getInt(first);

        int pre = arr[0];
        int rest = n_size - 1;
        for (int i=0;i<n_size-1;i++) {
            double tmp = (double)(target - pre) / rest;
            if (tmp < arr[i+1]) return getInt(tmp);
            pre += arr[i+1];
            rest--;
        }

        return arr[n_size-1];
    }
};

如果有问题,欢迎大家指正!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值