2023-08-30:用go语言编写。两个魔法卷轴问题。 给定一个数组arr,其中可能有正、负、0, 一个魔法卷轴可以把arr中连续的一段全变成0,你希望数组整体的累加和尽可能大。 你有两个魔法卷轴,
阅读原文时间:2023年08月31日阅读:1

2023-08-30:用go语言编写。两个魔法卷轴问题。

给定一个数组arr,其中可能有正、负、0,

一个魔法卷轴可以把arr中连续的一段全变成0,你希望数组整体的累加和尽可能大。

你有两个魔法卷轴,请返回数组尽可能大的累加和。

1 <= arr长度 <= 100000,

-100000 <= arr里的值 <= 100000。

来自微众银行。

来自左程云

答案2023-08-30:

算法maxSum1:

1.定义一个辅助函数max,用于返回两个数中的最大值。

2.定义函数maxSum1,接收一个整数数组arr作为参数,返回一个整数。

3.初始化变量p1为0,遍历数组arr,累加每个元素到p1。

4.获取数组arr的长度n。

5.调用函数mustOneScroll(arr, 0, n-1),返回一个整数,并赋值给变量p2。

6.初始化变量p3为math.MinInt32。

7.循环变量i从1到n-1:

  • 调用函数mustOneScroll(arr, 0, i-1),返回一个整数,并与调用函数mustOneScroll(arr, i, n-1)的返回值相加,得到一个新的整数。

  • 调用max函数,将p3与新整数比较,取较大值赋给p3。

8.调用max函数三次,分别比较p1、p2和p3的值,返回最大值作为结果。

算法maxSum2:

1.定义一个辅助函数max,用于返回两个数中的最大值。

2.定义函数maxSum2,接收一个整数数组arr作为参数,返回一个整数。

3.如果数组arr的长度为0,直接返回0。

4.初始化变量p1为0,遍历数组arr,累加每个元素到p1。

5.获取数组arr的长度n。

6.创建长度为n的数组left,用于存储每个位置左边范围内的最大累加和。

7.初始化变量sum为arr[0],maxSum为max(0, sum)。

8.循环变量i从1到n-1:

  • 将left[i]设置为max(left[i-1]+arr[i], maxSum)。

  • 累加arr[i]到sum。

  • 用max函数比较maxSum和sum的值,将较大值赋给maxSum。

9.创建长度为n的数组right,用于存储每个位置右边范围内的最大累加和。

10.初始化变量sum为arr[n-1],maxSum为max(0, sum)。

11.倒序循环变量i从n-2到0:

- 将right[i]设置为max(arr[i]+right[i+1], maxSum)。

- 累加arr[i]到sum。

- 用max函数比较maxSum和sum的值,将较大值赋给maxSum。

12.初始化变量p2为left[n-1]。

13.初始化变量p3为math.MinInt32。

14.循环变量i从1到n-1:

- 将left[i-1]+right[i]的值与p3比较,取较大值赋给p3。

15.调用max函数三次,分别比较p1、p2和p3的值,返回最大值作为结果。

时间复杂度和空间复杂度:

  • 对于maxSum1算法,时间复杂度为O(N^3),其中N为数组arr的长度。空间复杂度为O(1)。

  • 对于maxSum2算法,时间复杂度为O(N),其中N为数组arr的长度。空间复杂度为O(N)(需要额外的left和right数组)。

go完整代码如下:

package main

import (
    "fmt"
    "math"
    "math/rand"
    "time"
)

// 暴力方法
// 为了测试
func maxSum1(arr []int) int {
    p1 := 0
    for _, num := range arr {
        p1 += num
    }
    n := len(arr)
    p2 := mustOneScroll(arr, 0, n-1)
    p3 := math.MinInt32
    for i := 1; i < n; i++ {
        p3 = max(p3, mustOneScroll(arr, 0, i-1)+mustOneScroll(arr, i, n-1))
    }
    return max(p1, max(p2, p3))
}

// 为了测试
func mustOneScroll(arr []int, L, R int) int {
    ans := math.MinInt32
    for a := L; a <= R; a++ {
        for b := a; b <= R; b++ {
            curAns := 0
            for i := L; i < a; i++ {
                curAns += arr[i]
            }
            for i := b + 1; i <= R; i++ {
                curAns += arr[i]
            }
            ans = max(ans, curAns)
        }
    }
    return ans
}

// 正式方法
// 时间复杂度O(N)
func maxSum2(arr []int) int {
    if len(arr) == 0 {
        return 0
    }
    // 一个卷轴也不用
    p1 := 0
    for _, num := range arr {
        p1 += num
    }
    n := len(arr)
    // left[i] : 0 ~ i范围上,一定要用一次卷轴的情况下,最大累加和多少
    left := make([]int, n)
    // left[0] = 0 : 0 ~ 0,一定要用一次卷轴的情况下,最大累加和多少
    // 每一步的前缀和
    // 0~0 前缀和
    sum := arr[0]
    // 之前所有前缀和的,最大值
    maxSum := max(0, sum)
    for i := 1; i < n; i++ {
        // left[i - 1] + arr[i]
        // maxSum : 之前所有前缀和的,最大值
        left[i] = max(left[i-1]+arr[i], maxSum)
        sum += arr[i]
        maxSum = max(maxSum, sum)
    }
    // 只用一次卷轴,必须用,0~n-1范围上的解,第二种可能性
    p2 := left[n-1]
    // 第三种 :一定要用两次卷轴
    right := make([]int, n)
    // right[i] : i ~ n-1范围上,一定要用一次卷轴的情况下,最大累加和多少
    sum = arr[n-1]
    maxSum = max(0, sum)
    for i := n - 2; i >= 0; i-- {
        right[i] = max(arr[i]+right[i+1], maxSum)
        sum += arr[i]
        maxSum = max(maxSum, sum)
    }
    p3 := math.MinInt32
    for i := 1; i < n; i++ {
        // 0..0 1...n-1
        // 0..1 2...n-1
        // 0..2 3...n-1
        p3 = max(p3, left[i-1]+right[i])
    }
    return max(p1, max(p2, p3))
}

// 辅助函数,返回两个数中的最大值
func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

// 为了测试
func randomArray(n, v int) []int {
    arr := make([]int, n)
    rand.Seed(time.Now().UnixNano())
    for i := 0; i < n; i++ {
        arr[i] = rand.Intn(2*v+1) - v
    }
    return arr
}

func main() {
    rand.Seed(time.Now().UnixMilli())
    N := 50
    V := 100
    testTimes := 10000
    fmt.Println("测试开始")
    for i := 0; i < testTimes; i++ {
        n := rand.Intn(N)
        arr := randomArray(n, V)
        ans1 := maxSum1(arr)
        ans2 := maxSum2(arr)
        if ans1 != ans2 {
            fmt.Println("出错了!")
        }
    }
    fmt.Println("测试结束")
}

rust完整代码如下:

use std::cmp;

// 暴力方法
// 为了测试
fn max_sum1(arr: &[i32]) -> i32 {
    let mut p1 = 0;
    for &num in arr {
        p1 += num;
    }
    let n = arr.len() as i32;
    let mut p2 = must_one_scroll(arr, 0, n - 1);
    let mut p3 = i32::MIN;
    for i in 1..n {
        p3 = cmp::max(
            p3,
            must_one_scroll(arr, 0, i - 1) + must_one_scroll(arr, i, n - 1),
        );
    }
    cmp::max(p1, cmp::max(p2, p3))
}

// 为了测试
fn must_one_scroll(arr: &[i32], l: i32, r: i32) -> i32 {
    let mut ans = i32::MIN;
    for a in l..=r {
        for b in a..=r {
            let mut cur_ans = 0;
            for i in l..a {
                cur_ans += arr[i as usize];
            }
            for i in b + 1..=r {
                cur_ans += arr[i as usize];
            }
            ans = cmp::max(ans, cur_ans);
        }
    }
    ans
}

// 正式方法
// 时间复杂度O(N)
fn max_sum2(arr: &[i32]) -> i32 {
    if arr.is_empty() {
        return 0;
    }
    // 一个卷轴也不用
    let mut p1 = 0;
    for &num in arr {
        p1 += num;
    }
    let n = arr.len() as i32;
    // left[i] : 0 ~ i范围上,一定要用一次卷轴的情况下,最大累加和多少
    let mut left = vec![0; n as usize];
    // left[0] = 0 : 0 ~ 0,一定要用一次卷轴的情况下,最大累加和多少
    // 每一步的前缀和
    // 0~0 前缀和
    let mut sum = arr[0];
    // 之前所有前缀和的,最大值
    let mut max_sum = cmp::max(0, sum);
    for i in 1..n {
        // left[i - 1] + arr[i]
        // max_sum : 之前所有前缀和的,最大值
        left[i as usize] = cmp::max(left[i as usize - 1] + arr[i as usize], max_sum);
        sum += arr[i as usize];
        max_sum = cmp::max(max_sum, sum);
    }
    // 只用一次卷轴,必须用,0~n-1范围上的解,第二种可能性
    let p2 = left[n as usize - 1];
    // 第三种 :一定要用两次卷轴
    let mut right = vec![0; n as usize];
    // right[i] : i ~ n-1范围上,一定要用一次卷轴的情况下,最大累加和多少
    sum = arr[n as usize - 1];
    max_sum = cmp::max(0, sum);
    for i in (0..n - 1).rev() {
        right[i as usize] = cmp::max(arr[i as usize] + right[i as usize + 1], max_sum);
        sum += arr[i as usize];
        max_sum = cmp::max(max_sum, sum);
    }
    let mut p3 = i32::MIN;
    for i in 1..n {
        // 0..0 1...n-1
        // 0..1 2...n-1
        // 0..2 3...n-1
        p3 = cmp::max(p3, left[i as usize - 1] + right[i as usize]);
    }
    cmp::max(p1, cmp::max(p2, p3))
}

// 为了测试
fn random_array(n: usize, v: i32) -> Vec<i32> {
    let mut arr = vec![0; n];
    for i in 0..n {
        arr[i] = (rand::random::<i32>() % (v * 2 + 1)) - v;
    }
    arr
}

// 为了测试
fn main() {
    let n = 50;
    let v = 100;
    let test_times = 10_000;
    println!("测试开始");
    for _ in 0..test_times {
        let n = rand::random::<usize>() % n;
        let arr = random_array(n, v);
        let ans1 = max_sum1(&arr);
        let ans2 = max_sum2(&arr);
        if ans1 != ans2 {
            println!("出错了!");
        }
    }
    println!("测试结束");
}

c++完整代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;

int mustOneScroll(vector<int>& arr, int L, int R) {
    int ans = INT_MIN;
    for (int a = L; a <= R; a++) {
        for (int b = a; b <= R; b++) {
            int curAns = 0;
            for (int i = L; i < a; i++) {
                curAns += arr[i];
            }
            for (int i = b + 1; i <= R; i++) {
                curAns += arr[i];
            }
            ans = max(ans, curAns);
        }
    }
    return ans;
}

int maxSum1(vector<int>& arr) {
    int p1 = 0;
    for (int num : arr) {
        p1 += num;
    }
    int n = arr.size();
    int p2 = mustOneScroll(arr, 0, n - 1);
    int p3 = INT_MIN;
    for (int i = 1; i < n; i++) {
        p3 = max(p3, mustOneScroll(arr, 0, i - 1) + mustOneScroll(arr, i, n - 1));
    }
    return max(p1, max(p2, p3));
}

int maxSum2(vector<int>& arr) {
    if (arr.size() == 0) {
        return 0;
    }
    int p1 = 0;
    for (int num : arr) {
        p1 += num;
    }
    int n = arr.size();
    vector<int> left(n);
    int sum = arr[0];
    int maxSum = max(0, sum);
    for (int i = 1; i < n; i++) {
        left[i] = max(left[i - 1] + arr[i], maxSum);
        sum += arr[i];
        maxSum = max(maxSum, sum);
    }
    int p2 = left[n - 1];
    vector<int> right(n);
    sum = arr[n - 1];
    maxSum = max(0, sum);
    for (int i = n - 2; i >= 0; i--) {
        right[i] = max(arr[i] + right[i + 1], maxSum);
        sum += arr[i];
        maxSum = max(maxSum, sum);
    }
    int p3 = INT_MIN;
    for (int i = 1; i < n; i++) {
        p3 = max(p3, left[i - 1] + right[i]);
    }
    return max(p1, max(p2, p3));
}

vector<int> randomArray(int n, int v) {
    vector<int> arr(n);
    for (int i = 0; i < n; i++) {
        arr[i] = rand() % (2 * v + 1) - v;
    }
    return arr;
}

int main() {
    int N = 50;
    int V = 100;
    int testTimes = 10000;
    cout << "测试开始" << endl;
    for (int i = 0; i < testTimes; i++) {
        int n = rand() % N;
        vector<int> arr = randomArray(n, V);
        int ans1 = maxSum1(arr);
        int ans2 = maxSum2(arr);
        if (ans1 != ans2) {
            cout << "出错了!" << endl;
        }
    }
    cout << "测试结束" << endl;
    return 0;
}

c完整代码如下:

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

int maxSum1(int* arr, int n);
int mustOneScroll(int* arr, int L, int R);
int maxSum2(int* arr, int n);
int* randomArray(int n, int v);

int maxSum1(int* arr, int n) {
    int p1 = 0;
    int* ptr = arr;
    for (int i = 0; i < n; i++) {
        p1 += *ptr++;
    }
    int p2 = mustOneScroll(arr, 0, n - 1);
    int p3 = -INT_MAX;
    for (int i = 1; i < n; i++) {
        p3 = (p3 > mustOneScroll(arr, 0, i - 1) + mustOneScroll(arr, i, n - 1)) ? p3 : mustOneScroll(arr, 0, i - 1) + mustOneScroll(arr, i, n - 1);
    }
    return (p1 > (p2 > p3 ? p2 : p3)) ? p1 : ((p2 > p3) ? p2 : p3);
}

int mustOneScroll(int* arr, int L, int R) {
    int ans = -INT_MAX;
    for (int a = L; a <= R; a++) {
        for (int b = a; b <= R; b++) {
            int curAns = 0;
            for (int i = L; i < a; i++) {
                curAns += *(arr + i);
            }
            for (int i = b + 1; i <= R; i++) {
                curAns += *(arr + i);
            }
            ans = (ans > curAns) ? ans : curAns;
        }
    }
    return ans;
}

int maxSum2(int* arr, int n) {
    if (n == 0) {
        return 0;
    }
    int p1 = 0;
    int* ptr = arr;
    for (int i = 0; i < n; i++) {
        p1 += *ptr++;
    }
    int* left = (int*)malloc(n * sizeof(int));
    int* right = (int*)malloc(n * sizeof(int));
    int sum, maxSum;

    sum = *arr;
    maxSum = (0 > sum) ? 0 : sum;
    *left = (0 > (*arr)) ? 0 : (*arr);
    for (int i = 1; i < n; i++) {
        *(left + i) = (*(left + i - 1) + *(arr + i) > maxSum) ? *(left + i - 1) + *(arr + i) : maxSum;
        sum += *(arr + i);
        maxSum = (maxSum > sum) ? maxSum : sum;
    }

    int p2 = *(left + (n - 1));

    sum = *(arr + (n - 1));
    maxSum = (0 > sum) ? 0 : sum;
    *(right + (n - 1)) = (0 > (*(arr + (n - 1)))) ? 0 : (*(arr + (n - 1)));
    for (int i = n - 2; i >= 0; i--) {
        *(right + i) = (*(arr + i) + *(right + i + 1) > maxSum) ? (*(arr + i) + *(right + i + 1)) : maxSum;
        sum += *(arr + i);
        maxSum = (maxSum > sum) ? maxSum : sum;
    }

    int p3 = -INT_MAX;
    for (int i = 1; i < n; i++) {
        p3 = (p3 > (*(left + i - 1) + *(right + i))) ? p3 : (*(left + i - 1) + *(right + i));
    }

    int result = (p1 > (p2 > p3 ? p2 : p3)) ? p1 : ((p2 > p3) ? p2 : p3);

    free(left);
    free(right);

    return result;
}

int* randomArray(int n, int v) {
    int* arr = (int*)malloc(n * sizeof(int));
    int* ptr = arr;
    for (int i = 0; i < n; i++) {
        *ptr++ = (rand() % (2 * v + 1)) - v;
    }
    return arr;
}

int main() {
    int N = 50;
    int V = 100;
    int testTimes = 10000;
    printf("测试开始\n");
    for (int i = 0; i < testTimes; i++) {
        int n = rand() % N;
        int* arr = randomArray(n, V);
        int ans1 = maxSum1(arr, n);
        int ans2 = maxSum2(arr, n);
        if (ans1 != ans2) {
            printf("出错了!\n");
        }
        free(arr);
    }
    printf("测试结束\n");
    return 0;
}