当前位置: 首页 > news >正文

华为OD机试 - 几何平均值最大子数(Python/JS/C/C++ 2024 E卷 200分)

在这里插入图片描述

华为OD机试 2024E卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

从一个长度为N的正整数数组numbers中找出长度至少为L且几何平均值Q最大的子数组,并输出其位置和大小。(K个数的几何平均值为K个数的乘积的K次方根)

若有多个子数组的几何平均值均为最大值Q,则输出长度最小的子数组。

若有多个长度最小的子数组的几何平均值均为最大值,则输出最前面的子数组。

二、输入描述

第1行输入N、L:

N表示numbers的大小(1 <= N <= 100000)

L表示子数组的最小长度(1 <= L <= N)

之后N行表示numbers中的N个数,每行一个(1 <= numbers[i] <= 10^9)

三、输出描述

输出子数组的位置(从0开始计数)和大小,中间用一个空格隔开。

备注
用例保证除几何平均值为最大值的子数组外,其他子数组的几何平均值至少比最大值小10^-10倍。

四、测试用例

测试用例1:

1、输入

3 2
2
2
3

2、输出

1 2

3、说明

长度至少为2的子数组共有三个,分别是{2,2}, {2,3}, {2,3},其中{2,3}的几何平均值最大,故输出其位置1和长度2。

测试用例2:

1、输入

10 2
0.2
0.2
0.1
0.2
0.2
0.2
0.1
0.2
0.2
0.2

2、输出

0 2

3、说明

所有长度为2的子数组及其几何平均值:

索引0-1: [0.2, 0.2],GM = 0.2
索引1-2: [0.2, 0.1],GM ≈ 0.141
索引2-3: [0.1, 0.2],GM ≈ 0.141
索引3-4: [0.2, 0.2],GM = 0.2
索引4-5: [0.2, 0.2],GM = 0.2
索引5-6: [0.2, 0.1],GM ≈ 0.141
索引6-7: [0.1, 0.2],GM ≈ 0.141
索引7-8: [0.2, 0.2],GM = 0.2
索引8-9: [0.2, 0.2],GM = 0.2

最大几何平均值为0.2,对应多个子数组。选择最早的子数组,即从索引0开始的子数组,因此输出0 2。

五、解题思路

1、问题分析

我们需要在一个长度为N的正数数组numbers中找出长度至少为L且几何平均值最大的子数组,并输出其起始位置和长度。如果存在多个满足条件的子数组,我们需要按照以下优先级选择:

  1. 几何平均值最大的子数组。
  2. 如果有多个几何平均值相同,选择长度最小的子数组。
  3. 如果仍有多个,选择最前面的子数组。

由于N的范围较大(1 ≤ N ≤ 100,000),需要设计一个高效的算法。

2、具体步骤:

  1. 读取输入:读取N和L,接着读取N个正数。
  2. 对数转换:对每个数取自然对数,存储在一个数组中。
  3. 前缀和计算:计算对数数组的前缀和,以便快速计算任意子数组的对数和。
  4. 滑动窗口遍历:遍历所有长度为L的子数组,计算其对数和,记录最大对数和及其起始位置。
  5. 输出结果:输出起始位置和子数组长度L。

六、Python算法源码

import math
import sysdef main():# 读取输入input = sys.stdin.read().split()index = 0# 读取数组大小N和子数组最小长度LN = int(input[index])index += 1L = int(input[index])index += 1# 初始化数组并计算对数值log_values = []for _ in range(N):num = float(input[index])index += 1log_values.append(math.log(num))  # 计算每个数的自然对数# 计算前缀和数组prefix_sums = [0.0] * (N + 1)for i in range(1, N + 1):prefix_sums[i] = prefix_sums[i - 1] + log_values[i - 1]# 初始化最大对数平均值及对应子数组的起始位置和长度max_log_average = -math.infresult_start_index = 0result_length = L# 初始化最小前缀和及其索引min_prefix = 0.0min_prefix_index = 0# 遍历前缀和数组,寻找最大对数平均值的子数组for i in range(L, N + 1):# 更新最小前缀和为[0, i - L]区间的最小前缀和if prefix_sums[i - L] < min_prefix:min_prefix = prefix_sums[i - L]min_prefix_index = i - L# 计算当前对数平均值current_log_average = (prefix_sums[i] - min_prefix) / L# 更新最大对数平均值及对应的子数组位置和长度if current_log_average > max_log_average:max_log_average = current_log_averageresult_start_index = min_prefix_indexresult_length = Lelif math.isclose(current_log_average, max_log_average, abs_tol=1e-10):# 如果对数平均值相同,选择长度更小的子数组if L < result_length:result_start_index = min_prefix_indexresult_length = L# 如果长度相同,选择起始位置更靠前的子数组(无需操作,因为遍历顺序已保证)# 输出结果print(result_start_index, result_length)if __name__ == "__main__":main()

七、JavaScript算法源码

// 引入readline模块以读取输入
const readline = require('readline');const rl = readline.createInterface({input: process.stdin,output: process.stdout
});let input = [];
rl.on('line', function(line){input = input.concat(line.trim().split(' '));
}).on('close', function(){let index = 0;// 读取数组大小N和子数组最小长度Lconst N = parseInt(input[index++]);const L = parseInt(input[index++]);// 初始化数组并计算对数值const logValues = [];for(let i = 0; i < N; i++){const num = parseFloat(input[index++]);logValues.push(Math.log(num)); // 计算每个数的自然对数}// 计算前缀和数组const prefixSums = new Array(N + 1).fill(0);for(let i = 1; i <= N; i++){prefixSums[i] = prefixSums[i - 1] + logValues[i - 1];}// 初始化最大对数平均值及对应子数组的起始位置和长度let maxLogAverage = -Infinity;let resultStartIndex = 0;let resultLength = L;// 初始化最小前缀和及其索引let minPrefix = 0.0;let minPrefixIndex = 0;// 遍历前缀和数组,寻找最大对数平均值的子数组for(let i = L; i <= N; i++){// 更新最小前缀和为[0, i - L]区间的最小前缀和if(prefixSums[i - L] < minPrefix){minPrefix = prefixSums[i - L];minPrefixIndex = i - L;}// 计算当前对数平均值const currentLogAverage = (prefixSums[i] - minPrefix) / L;// 更新最大对数平均值及对应的子数组位置和长度if(currentLogAverage > maxLogAverage){maxLogAverage = currentLogAverage;resultStartIndex = minPrefixIndex;resultLength = L;} else if(Math.abs(currentLogAverage - maxLogAverage) < 1e-10){// 如果对数平均值相同,选择长度更小的子数组if(L < resultLength){resultStartIndex = minPrefixIndex;resultLength = L;}// 如果长度相同,选择起始位置更靠前的子数组(无需操作,因为遍历顺序已保证)}}// 输出结果console.log(resultStartIndex + " " + resultLength);
});

八、C算法源码

#include <stdio.h>
#include <math.h>
#include <float.h>int main(){int N, L;// 读取数组大小N和子数组最小长度Lscanf("%d %d", &N, &L);double log_values[N];// 读取数组元素并计算对数值for(int i = 0; i < N; i++){double num;scanf("%lf", &num);log_values[i] = log(num); // 计算每个数的自然对数}// 计算前缀和数组double prefix_sums[N + 1];prefix_sums[0] = 0.0;for(int i = 1; i <= N; i++){prefix_sums[i] = prefix_sums[i - 1] + log_values[i - 1];}// 初始化最大对数平均值及对应子数组的起始位置和长度double max_log_average = -DBL_MAX;int result_start_index = 0;int result_length = L;// 初始化最小前缀和及其索引double min_prefix = 0.0;int min_prefix_index = 0;// 遍历前缀和数组,寻找最大对数平均值的子数组for(int i = L; i <= N; i++){// 更新最小前缀和为[0, i - L]区间的最小前缀和if(prefix_sums[i - L] < min_prefix){min_prefix = prefix_sums[i - L];min_prefix_index = i - L;}// 计算当前对数平均值double current_log_average = (prefix_sums[i] - min_prefix) / L;// 更新最大对数平均值及对应的子数组位置和长度if(current_log_average > max_log_average){max_log_average = current_log_average;result_start_index = min_prefix_index;result_length = L;}else if(fabs(current_log_average - max_log_average) < 1e-10){// 如果对数平均值相同,选择长度更小的子数组if(L < result_length){result_start_index = min_prefix_index;result_length = L;}// 如果长度相同,选择起始位置更靠前的子数组(无需操作,因为遍历顺序已保证)}}// 输出结果printf("%d %d\n", result_start_index, result_length);return 0;
}

九、C++算法源码

#include <bits/stdc++.h>
using namespace std;int main(){ios::sync_with_stdio(false);cin.tie(0);int N, L;// 读取数组大小N和子数组最小长度Lcin >> N >> L;vector<double> log_values(N);// 读取数组元素并计算对数值for(int i = 0; i < N; i++){double num;cin >> num;log_values[i] = log(num); // 计算每个数的自然对数}// 计算前缀和数组vector<double> prefix_sums(N + 1, 0.0);for(int i = 1; i <= N; i++){prefix_sums[i] = prefix_sums[i - 1] + log_values[i - 1];}// 初始化最大对数平均值及对应子数组的起始位置和长度double max_log_average = -1e308; // 接近负无穷int result_start_index = 0;int result_length = L;// 初始化最小前缀和及其索引double min_prefix = 0.0;int min_prefix_index = 0;// 遍历前缀和数组,寻找最大对数平均值的子数组for(int i = L; i <= N; i++){// 更新最小前缀和为[0, i - L]区间的最小前缀和if(prefix_sums[i - L] < min_prefix){min_prefix = prefix_sums[i - L];min_prefix_index = i - L;}// 计算当前对数平均值double current_log_average = (prefix_sums[i] - min_prefix) / L;// 更新最大对数平均值及对应子数组的位置和长度if(current_log_average > max_log_average){max_log_average = current_log_average;result_start_index = min_prefix_index;result_length = L;}else if(abs(current_log_average - max_log_average) < 1e-10){// 如果对数平均值相同,选择长度更小的子数组if(L < result_length){result_start_index = min_prefix_index;result_length = L;}// 如果长度相同,选择起始位置更靠前的子数组(无需操作,因为遍历顺序已保证)}}// 输出结果cout << result_start_index << " " << result_length << "\n";return 0;
}

🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述


http://www.mrgr.cn/news/43674.html

相关文章:

  • vue实现token的无感刷新
  • 振动分析-30-振动信号的幅值概率密度函数CWRU西楚大学轴承数据(实战)
  • rk3568 LTE(EC20 Android14)
  • C语言 | Leetcode C语言题解之第459题重复的子字符串
  • PMP--冲刺题--解题--11-20
  • Anaconda的安装与环境设置
  • 【AI自然语言处理应用】通过API调用通义晓蜜CCAI-对话分析AIO应用
  • 【分布式微服务云原生】深入剖析Redis缓存问题及其解决方案
  • Python网络编程:开启你的网络之旅
  • 基于Springboot+Android的的电子书阅读器系统的设计与实现(含源码+数据库)
  • C++ | Leetcode C++题解之第459题重复的子字符串
  • 设计模式、系统设计 record part03
  • stm32 使用 rt-thread 引脚PIN中断设置边沿触发问题
  • 付费计量系统数据元素(Data elements)
  • llm接口高可用工程实践(尽快关注我,以后这些文章将只对粉丝开放)
  • WSL2Linux 子系统(十二)
  • we3.0里的钱包是什么?
  • CANoe_TestModule截图功能TestReportAddWindowCapture
  • HTML5 新元素
  • 【C++】关键字+命名空间