携程2023秋招笔试 最小平滑值(C++ 贪心)

题目描述

游游得到了一个有 n n n 个数字的数列。
游游定义了“平滑值”的概念:平滑值指任意两个相邻的数的差的绝对值的最大值。例如
[1, 2, 5, 7, 8]的平滑值是3。
游游现在想知道,在只修改一个位置的数字(可以修改为任意值) 或者不修改的情况下,数列的平滑值最小是多少?

输入描述:

第一行包含一个数字 n n n 代表数列的数字个数。
第二行包含 n n n 个数字,代表数列 a。
2 ≤ n ≤ 1 0 5 2\le n\le 10^5 2n105
− 1 0 9 ≤ a i ≤ 1 0 9 -10^9\le a_i\le 10^9 109ai109

输出描述

输出一个整数,代表数列最小的平滑值。

示例1

输入:

3
1 3 4

输出:

1

说明:

将第一个数字修改为 3 3 3,平滑值变为 1 1 1,可以证明这是最优的方案之一。

示例2

输入:

5
-1 1 2 5 7

输出:

2

说明:

将第三个数字修改为 3 3 3,平滑值变为 2 2 2,可以证明这是最优的方案。

分析 1

  1. 首先,我们肯定要改最大的那一对,假设为 a[i]a[j] ,且 a[i] > a[j],那就有两种改法:
    • 大的慢慢变小
    • 小的慢慢变大

(不可一蹴而就,一点一点改)

  1. 每改完一次a[i], 和a[j],次大值最大值都有可能改变:假设次大值为a[n]a[m],i, j 和 n, m可能有重合部分,次大值可能随最大值变大而变小,也可能一起变大,反之亦然。 如果最大、次大都变成0,那就得看次次大值,难道要记录前三大的值吗?这就太麻烦了,只能贪心。

结论:这个思路行不通❌❌❌。

分析 2

直接找最大的,设 ∣    a [ i ] − a [ i − 1 ]    ∣ | \ \ a[i] - a[i-1] \ \ |   a[i]a[i1]   为最大:

  1. i = n - 1,即这两个值在最右边,就令a[i] = a[i],然后再求一遍最小值。
  2. i - 1 = 0,即这两个值在最左边,就令a[i - 1] = a[i],然后再求一遍最小值。
  3. 若在中间,则令 a[i - 1] = (a[i - 2] + a[i]) / 2,求一次最小值,复原数组。a[i] = (a[i - 1] + a[i + 1]) / 2,再求一遍最小值。即,左右两个值,各变成自身左右相邻值的和的一半。 相当于,把数列的凹凸给磨平

代码

#include <iostream>
#include <iterator>
#include <vector>

using namespace std;

void find_max(vector<int> a, int &max, int &index) { // 就是个找最大值的
    max = index = -1;
    int tmp;
    for (int i = 1; i < a.size(); i++) {
        tmp = a[i] - a[i - 1];
        if (tmp > max) {
            max = tmp;
            index = i;
        }
    }
}

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    int ans, max, index;
    find_max(a, max, index); // 找到最大值,和第二个元素的index
    ans = max;
    if (index == n - 1) {
        a[index] = a[index - 1];
        find_max(a, max, index);
        ans = max < ans ? max : ans;
    } 
    if (index - 1 == 0) {
        a[index - 1] = a[index];
        find_max(a, max, index);
        ans = max < ans ? max : ans;
    }
    if (index != n - 1 && index - 1 != 0) {
        int tmp = a[index - 1];
        a[index - 1] = (a[index - 2] + a[index]) / 2;
        find_max(a, max, index);
        ans = max < ans ? max : ans;
        a[index - 1] = tmp; // 复原
        a[index] = (a[index - 1] + a[index + 1]) / 2;
        find_max(a, max, index);
        ans = max < ans ? max : ans;
    }
    cout << ans;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值