leetcode 1300. 转变数组后最接近目标值的数组和(前缀和+二分)

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

请注意,答案不一定是 arr 中的数字。

示例 1:
输入:arr = [4,9,3], target = 10
输出:3
解释:当选择 value 为 3 时,数组会变成 [3, 3, 3],和为 9 ,这是最接近 target 的方案。

示例 2:
输入:arr = [2,3,5], target = 10
输出:5

示例 3:
输入:arr = [60864,25176,27249,21296,20204], target = 56803
输出:11361

提示:
1 <= arr.length <= 10^4
1 <= arr[i], target <= 10^5

思路:
首先进行排序,让数据符合可二分性,求得前缀和,二分大小的下标做为条件求和,然后再二分答案,整体时间复杂度 O ( n l o g n ) + O ( l o g n ∗ l o g n ) O(nlogn)+O(logn*logn) O(nlogn)+O(lognlogn) ,当然这题可以两层for循环过掉,(1e4*1e4)的时间复杂度正常计算机可以跑完

写了40~50分钟的代码:仅供参考

#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long ll;
const int inf = 1 << 30;
const int maxn = 2e5 + 5;
const int N = 1e3 + 5;
const int base = 131;
//vector<vector<int>> vec;
int a[maxn], sum[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, target;
    cin >> n >> target;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++)
        sum[i] = sum[i - 1] + a[i];
    int l = 0, r = 100000000, minx = 200000000;
    int ans = a[n];
    if (sum[n] <= target)
    {
        cout << ans << endl;
        return 0;
    }
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        int x = lower_bound(a + 1, a + 1 + n, mid) - a;
        int su = sum[x - 1] + (n - x + 1) * mid;
        if (abs(su - target) < minx)
            minx = abs(su - target), ans = mid;
        else if (abs(su - target) == minx)
            ans = min(ans, mid);
        if (su >= target)
            r = mid - 1;
        else
            l = mid + 1;
    }
    cout << ans << endl;
}

以leetcode形式提交:

class Solution {
int a[10005], sum[10005];
public:
    int findBestValue(vector<int>& arr, int target) {
        int n=arr.size();
     for (int i = 1; i <= n; i++)
        a[i]=arr[i-1];
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++)
        sum[i] = sum[i - 1] + a[i];
    int l = 0, r = 100000000, minx = 200000000;
    int ans = r;
    if(sum[n]<=target)
     return a[n];
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        int x = lower_bound(a + 1, a + 1 + n, mid) - a;
        int su = sum[x - 1] + (n - x + 1) * mid;
        if (abs(su - target) < minx)
            minx = abs(su - target), ans = mid;
        else if (abs(su - target) == minx)
            ans = min(ans, mid);
        if (su >= target)
            r = mid - 1;
        else
            l = mid + 1;
    } return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值