由 8 个或更多位置分隔的数组中两个元素的最大乘积

Posted

技术标签:

【中文标题】由 8 个或更多位置分隔的数组中两个元素的最大乘积【英文标题】:Maximum product of two elements in an array separated by 8 or more positions 【发布时间】:2016-03-19 16:11:31 【问题描述】:

这是我目前遇到的问题和代码。

我有一个正数序列。序列的长度大于 8,负数(不是序列的一部分)是序列结束的标志。我需要编写一个程序(按时间和内存使用量有效),找到由 8 个或更多位置分隔的 2 个元素的最大乘积。保证答案小于2000000000。

例如,对于1 2 3 4 5 6 7 8 9 10 -1,答案将是20

我的代码:

#include <stdio.h>
#include <stdlib.h>

static long long int find_max(long int *v1, long int size) 
    const int d = 8;
    long int arr[8];
    long int maxi = 0;  
    long long int max_pr = 0;

    for (int i = 1; i < d + 1; i++) 
        arr[i % d] = v1[i - 1];
    
    for (int j = d + 1; j < size + 1; j++) 
        if (arr[j % d] > maxi)
            maxi = arr[j % d];
        if (v1[j - 1] * maxi > max_pr)
            max_pr = v1[j - 1] * maxi;
        arr[j % d] = v1[j - 1];
    
    return max_pr;


int main() 
    long int seq[100000];
    long int n = 0;

    while (n < 100000 && scanf("%ld", &seq[n]) == 1) 
        if (seq[n] < 0) 
            break;    //vector.push_back was too slow
        
        n++;
    

    long long int answer = find_max(seq, n);
    printf("%lld ", answer);

    return 0;

这是一门与我的学位无关的算法和数据结构公开课程的家庭作业。我的代码在测试系统上失败。我已经尝试解决这个问题几天了,但无法理解我在这里做错了什么,因为它对于我能想出的每个示例都运行良好。

非常感谢任何帮助。

【问题讨论】:

今后请保持理智的大括号风格。您的代码以前无法阅读。 另外,我们能得到一个提示吗?你能提供一个失败的测试用例吗?你的代码到底有什么问题? @ReousaAsteron 这是任务描述的一部分。仅用作序列结束的标志,因为它的长度是未知的。是的,去掉就好了 @Barry 我不知道出了什么问题,不幸的是,我没有任何测试用例示例。我将它发送到我的课程的在线测试系统,它只说它在测试 8 中失败并给出了错误的答案 您假设序列的长度最多为100000。为什么?正如 gnasher729 的回答所示,您不需要分配一个数组来存储整个序列。如果序列包含超过 100000 个元素,您的代码肯定会失败。 【参考方案1】:

这很容易在线性时间内完成,不需要任何额外的存储空间。想想哪些数字可能是可能的解决方案:它可能是第一个数字乘以第九个数字。它可能是前两个中最大的一个,是第十个的倍数。它可能是前三个中最大的,乘以第十一个,依此类推。所以:

Set maxN = 0, maxProduct = 0, i = 0. 
As long as v1 [i + 8] ≥ 0:
    If v1 [i] > maxN then maxN = v1 [i]
    If v1 [i + 8] * maxN > maxProduct then maxProduct = v1 [i + 8] * maxN.
    Let i = i + 1.

就是这样。

【讨论】:

谢谢!我知道这是一项简单的任务,并且我从逻辑上理解它应该如何完成。我在这里发布的内容实际上并不是我尝试过的第一件事。您的解决方案在我的代码失败的同一测试中失败 @marinazz:如果您知道这是一项简单的任务,并且您从逻辑上理解它应该如何完成,那么您为什么做得这么糟糕?将所有元素读入数组是一件愚蠢的事情。 @TonyK 我的意思是我理解算法。我仍然不明白如果不将它们读入数组或向量中,我应该如何从输入中获取元素。我是一个绝对的初学者,即使我的整个问题都很愚蠢,也没有必要粗鲁。 @marinazzz:嗯,我很清楚 gnasher729 的算法只需要你存储最后 8 个值。【参考方案2】:

您的算法没有按照问题要求您执行的操作。特别是,arr[8]i%d 不是必需的。

以下是如何在 O(n) 时间内解决此问题,并且效率最高:

创建一个大小等于数组大小的数组maxSoFar 从左到右遍历数组seq。将maxSoFar[i] 设置为seq 的最大值在i 的左侧 再次从索引8 开始遍历数组seq,并找到seq[i] * maxSoFar[i-8] 中的max

这是一个随机序列的maxSoFar 示例:

seq:             1 4 3 5 2 12  8  6 14 19  7  9 25 20 13
maxSoFar:        1 4 4 5 5 12 12 12 14 19 19 19 25 25 25

第二遍应该产生这些值:

seq:             1 4 3 5 2 12  8  6 14 19  7  9  25  20  13
maxSoFar[i-8]:   - - - - -  -  -  -  1  4  4  5   5  12  12
mul:             - - - - -  -  -  - 14 76 28 45 125 240 156

因此,结果是 240。

注意:数组maxSoFar可以去掉。你能看出来吗?

【讨论】:

不错,但不如 gnasher729 的优雅解决方案高效,因为您需要额外的 O(n) 空间来实现相同的时间复杂度。 感谢您的回复!我已经尝试了这里发布的两种解决方案,但没有一个通过了我的程序失败的相同测试。 我现在认为问题可能出在函数的 main() 部分。

以上是关于由 8 个或更多位置分隔的数组中两个元素的最大乘积的主要内容,如果未能解决你的问题,请参考以下文章

华为机试真题 Java 实现计算最大乘积

华为OD机试 - 计算最大乘积(Java) | 机试题+算法思路+考点+代码解析 2023

华为OD机试 - 计算最大乘积(Java) | 机试题+算法思路+考点+代码解析 2023

LeetCode 1460. 通过翻转子数组使两个数组相等 / 658. 找到 K 个最接近的元素 / 1464. 数组中两元素的最大乘积

LeetCode 1460. 通过翻转子数组使两个数组相等 / 658. 找到 K 个最接近的元素 / 1464. 数组中两元素的最大乘积

数组628. 三个数的最大乘积