青训营X豆包MarsCode 技术训练营刷题笔记3 | 豆包MarsCode AI 刷题

68 阅读3分钟

题目解析

题目描述

小R手上有一个长度为 n 的数组 (n > 0),数组中的元素分别来自集合 [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]。小R想从这个数组中选取一段连续的区间,得到可能的最大乘积。

你需要帮助小R找到最大乘积的区间,并输出这个区间的起始位置 x 和结束位置 y (x ≤ y)。如果存在多个区间乘积相同的情况,优先选择 x 更小的区间;如果 x 相同,选择 y 更小的区间。

注意:数组的起始位置为 1,结束位置为 n

题目分析

  1. 理解问题:我们需要找到数组中一段连续区间的最大乘积,并返回该区间的起始和结束位置。

  2. 数据结构选择:我们可以使用两个变量来记录当前的最大乘积和对应的区间。

  3. 算法步骤

    • 遍历数组,计算每个可能的区间的乘积。
    • 如果遇到0,则跳过该位置,因为0会使得乘积变为0。
    • 更新最大乘积和对应的区间。

解题思路

  • 动态规划的状态

    • 我们需要记录当前区间的最大乘积和最小乘积,因为数组中可能有负数。负数的乘积与负数相乘可以得到更大的值。
    • 使用两个数组 max_prodmin_prod 来分别记录以每个位置结尾的最大和最小乘积。
  • 状态转移

    • 如果当前元素是正数,最大乘积是 max(arr[i], max_prod[i-1] * arr[i]),最小乘积是 min(arr[i], min_prod[i-1] * arr[i])
    • 如果当前元素是负数,最大乘积是 max(arr[i], min_prod[i-1] * arr[i]),最小乘积是 min(arr[i], max_prod[i-1] * arr[i])
    • 如果当前元素是 0,最大和最小乘积都需要重新初始化为该元素本身。
  • 更新最大乘积的区间

    • 对于每个元素,更新当前区间的最大乘积,并记录对应的区间起始和结束位置。
  • 返回结果

    • 最后,返回最大乘积的起始和结束位置。

实现代码

#include <iostream>
#include <vector>
#include <climits>

using namespace std;

vector<int> solution(int n, vector<int> arr) {
    // 初始化最大乘积、最小乘积
    int max_prod = 1, min_prod = 1, global_max = INT_MIN;
    int temp_start = 0; // temp_start 用于记录潜在的起始位置
    int result_start = 0, result_end = 0;

    // 遍历数组
    for (int i = 0; i < n; ++i) {
        if (arr[i] == 0) {
            // 遇到零时,当前区间的乘积为0,重新开始
            if (0 > global_max) {
                global_max = 0;
                result_start = i;
                result_end = i;
            }
            // 重置最大和最小乘积
            max_prod = 1;
            min_prod = 1;
            temp_start = i + 1; // 下一段非零区间的开始
        } else {
            // 如果当前元素是负数,交换最大和最小乘积
            if (arr[i] < 0) {
                swap(max_prod, min_prod);
            }
            // 更新最大和最小乘积
            max_prod = max(arr[i], max_prod * arr[i]);
            min_prod = min(arr[i], min_prod * arr[i]);
        }

        // 如果当前的最大乘积大于之前的最大值,更新结果
        if (max_prod > global_max) {
            global_max = max_prod;
            result_start = temp_start;
            result_end = i;
        }
    }

    // 返回最大乘积区间的起始和结束位置(1-based)
    return {result_start + 1, result_end + 1};
}

int main() {
    // 测试用例
    cout << boolalpha << (solution(5, {1, 2, 4, 0, 8}) == vector<int>{1, 3}) << endl;  // [1, 3]
    cout << boolalpha << (solution(7, {1, 2, 4, 8, 0, 256, 0}) == vector<int>{6, 6}) << endl;  // [6, 6]
    cout << boolalpha << (solution(8, {1, 2, 4, 8, 0, 256, 512, 0}) == vector<int>{6, 7}) << endl;  // [6, 7]
    cout << boolalpha << (solution(7, {1, 2, 0, 0, 4, 8, 0}) == vector<int>{5, 6}) << endl;  // [5, 6]
    cout << boolalpha << (solution(11, {1024, 0, 2, 1, 0, 2, 128, 512, 4, 256, 256}) == vector<int>{6, 11}) << endl;  // [6, 11]
    return 0;
}