2023-11-25:用go语言,给定一个数组arr,长度为n,表示n个格子的分数

2023-11-25:用go语言,给定一个数组arr,长度为n,表示n个格子的分数,并且这些格子首尾相连,

孩子不能选相邻的格子,不能回头选,不能选超过一圈,

但是孩子可以决定从任何位置开始选,也可以什么都不选。

返回孩子能获得的最大分值。

1 <= n <= 10^6,

0 <= arr[i] <= 10^6。

来自华为od。

来自左程云

答案2023-11-25:

go和c++的代码用灵捷3.5编写,感觉有点抽风了,生成的代码需要修改才能运行。

大体过程如下:

1.暴力方法(max1函数)

这种方法是一种递归的方式,通过尝试所有可能的组合来找到最大分值。

  • 定义max1函数,接受一个长度为n的数组arr作为参数。

  • 若arr的长度为1,直接返回arr[]作为结果。

  • 否则,调用process函数,传入arr、起始索引和一个长度为n的布尔类型数组path(用于记录选择的路径)。

  • 在process函数中,先检查是否已经遍历到数组末尾,若是,则判断首尾是否相连,如果是则返回最小整数值math.MinInt32,否则遍历整个数组检查相邻格子是否被选中,如果有返回最小整数值。

  • 初始化ans为,遍历数组,如果path[j]为true,则将arr[j]加到ans上。

  • 返回ans作为结果。

2.记忆化搜索(max2函数)

这种方法使用动态规划的思想,借助一个二维数组dp来存储已计算的结果,以减少重复计算。

  • 定义max2函数,接受一个长度为n的数组arr作为参数。

  • 若arr的长度为1,直接返回arr[]作为结果。

  • 否则,初始化n为arr的长度,并创建一个二维数组dp,大小为[n][4],并将其所有元素设置为最小整数值math.MinInt32。

  • 初始化ans为arr[]加上调用process2函数的结果,传入arr、起始索引1、、和dp。

  • 将ans更新为ans与调用process2函数,传入arr、起始索引1、、和dp的结果中的较大值。

  • 返回ans作为结果。

3.正式方法(max3函数)

这种方法是一种严格位置依赖的动态规划方法,同时使用空间压缩技巧,减少额外空间的使用。

  • 定义max3函数,接受一个长度为n的数组arr作为参数。

  • 若arr的长度为1,直接返回arr[]作为结果。

  • 否则,初始化n为arr的长度,并创建两个大小为4的一维数组next和cur,用于保存计算过程中的结果。

  • 将next[]初始化为arr[n-1]的最大值和的较大值(即取和arr[n-1]的较大值)。

  • 从n-2开始向前遍历数组arr,进行动态规划计算。

  • 在每次遍历中,使用三重嵌套循环,遍历pre和end,计算cur[(pre<<1)|end]的值,其中<<为位运算符,|为按位或运算符。

  • 更新next数组的值为cur数组的值。

  • 最终,返回arr[]+next[3]和next[]中的较大值作为结果。

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

  • 第一种暴力方法的时间复杂度为O(2^n),空间复杂度为O(n)。

  • 第二种记忆化搜索的时间复杂度为O(n),空间复杂度为O(n)。

  • 第三种正式方法的时间复杂度为O(n),空间复杂度为O(1)。

go完整代码如下:

package main

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

// 暴力方法
func max1(arr []int) int {
    if len(arr) == 1 {
        return arr[0]
    }
    return process(arr, 0, make([]bool, len(arr)))
}

func process(arr []int, i int, path []bool) int {
    if i == len(arr) {
        if path[0] && path[len(arr)-1] {
            return math.MinInt32
        }
        for j := 1; j < len(arr); j++ {
            if path[j-1] && path[j] {
                return math.MinInt32
            }
        }
        ans := 0
        for j := 0; j < len(arr); j++ {
            if path[j] {
                ans += arr[j]
            }
        }
        return ans
    } else {
        path[i] = true
        ans1 := process(arr, i+1, path)
        path[i] = false
        ans2 := process(arr, i+1, path)
        return int(math.Max(float64(ans1), float64(ans2)))
    }
}

// 时间复杂度O(N),记忆化搜索
func max2(arr []int) int {
    if len(arr) == 1 {
        return arr[0]
    }
    n := len(arr)
    dp := make([][]int, n)
    for i := 0; i < n; i++ {
        dp[i] = make([]int, 4)
        for j := 0; j < 4; j++ {
            dp[i][j] = math.MinInt32
        }
    }
    ans := arr[0] + process2(arr, 1, 1, 1, dp)
    ans = int(math.Max(float64(ans), float64(process2(arr, 1, 0, 0, dp))))
    return ans
}

func process2(arr []int, i, pre, end int, dp [][]int) int {
    if i == len(arr)-1 {
        returnValue := 0
        if pre == 1 || end == 1 {
            return returnValue
        } else {
            return int(math.Max(float64(returnValue), float64(arr[i])))
        }
    } else {
        if dp[i][(pre<<1)|end] != math.MinInt32 {
            return dp[i][(pre<<1)|end]
        }
        p1 := process2(arr, i+1, 0, end, dp)
        p2 := math.MinInt32
        if pre != 1 {
            p2 = arr[i] + process2(arr, i+1, 1, end, dp)
        }
        ans := int(math.Max(float64(p1), float64(p2)))
        dp[i][(pre<<1)|end] = ans
        return ans
    }
}

// 正式方法
// 严格位置依赖的动态规划 + 空间压缩
// 时间复杂度O(N)
func max3(arr []int) int {
    if len(arr) == 1 {
        return arr[0]
    }
    n := len(arr)
    next := make([]int, 4)
    cur := make([]int, 4)
    next[0] = int(math.Max(0, float64(arr[n-1])))
    for i := n - 2; i >= 1; i-- {
        for pre := 0; pre < 2; pre++ {
            for end := 0; end < 2; end++ {
                cur[(pre<<1)|end] = next[end]
                if pre != 1 {
                    cur[(pre<<1)|end] = int(math.Max(float64(cur[(pre<<1)|end]), float64(arr[i]+next[2+end])))
                }
            }
        }
        next[0] = cur[0]
        next[1] = cur[1]
        next[2] = cur[2]
        next[3] = cur[3]
    }
    return int(math.Max(float64(arr[0]+next[3]), float64(next[0])))
}

// 为了测试
func randomArray(n, v int) []int {
    arr := make([]int, n)
    for i := 0; i < n; i++ {
        arr[i] = int(math.Floor(float64(v) * rand.Float64()))
    }
    return arr
}

func main() {
    N := 16
    V := 100
    testTimes := 500
    fmt.Println("测试开始")
    rand.Seed(time.Now().UnixMilli())
    for i := 0; i < testTimes; i++ {
        n := rand.Intn(N) + 1
        arr := randomArray(n, V)
        ans1 := max1(arr)
        ans2 := max2(arr)
        ans3 := max3(arr)
        if ans1 != ans2 || ans1 != ans3 {
            fmt.Println("出错了!", i)
            return
        }
    }
    fmt.Println("测试结束")
}

在这里插入图片描述

c++完整代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <ctime>

using namespace std;

int process(vector<int>& arr, int i, vector<bool>& path);

int max1(vector<int>& arr) {
    if (arr.size() == 1) {
        return arr[0];
    }
    vector<bool> a = vector<bool>(arr.size(), false);
    return process(arr,0 , a);
}

int process(vector<int>& arr, int i, vector<bool>& path) {
    if (i == arr.size()) {
        if (path[0] && path[arr.size() - 1]) {
            return INT32_MIN;
        }
        for (int j = 1; j < arr.size(); j++) {
            if (path[j - 1] && path[j]) {
                return INT32_MIN;
            }
        }
        int ans = 0;
        for (int j = 0; j < arr.size(); j++) {
            if (path[j]) {
                ans += arr[j];
            }
        }
        return ans;
    }
    else {
        path[i] = true;
        int ans1 = process(arr, i + 1, path);
        path[i] = false;
        int ans2 = process(arr, i + 1, path);
        return max(ans1, ans2);
    }
}

int process2(vector<int>& arr, int i, int pre, int end, vector<vector<int>>& dp);

int max2(vector<int>& arr) {
    if (arr.size() == 1) {
        return arr[0];
    }
    int n = arr.size();
    vector<vector<int>> dp(n, vector<int>(4, INT32_MIN));
    int ans = arr[0] + process2(arr, 1, 1, 1, dp);
    ans = max(ans, process2(arr, 1,0 ,0 , dp));
    return ans;
}

int process2(vector<int>& arr, int i, int pre, int end, vector<vector<int>>& dp) {
    if (i == arr.size() - 1) {
        int returnValue =0 ;
        if (pre == 1 || end == 1) {
            return returnValue;
        }
        else {
            return max(returnValue, arr[i]);
        }
    }
    else {
        if (dp[i][(pre << 1) | end] != INT32_MIN) {
            return dp[i][(pre << 1) | end];
        }
        int p1 = process2(arr, i + 1,0 , end, dp);
        int p2 = INT32_MIN;
        if (pre != 1) {
            p2 = arr[i] + process2(arr, i + 1, 1, end, dp);
        }
        int ans = max(p1, p2);
        dp[i][(pre << 1) | end] = ans;
        return ans;
    }
}

int max3(vector<int>& arr) {
    if (arr.size() == 1) {
        return arr[0];
    }
    int n = arr.size();
    vector<int> next(4);
    vector<int> cur(4);
    next[0] = max(0, arr[n - 1]);
    for (int i = n - 2; i >= 1; i--) {
        for (int pre = 0; pre < 2; pre++) {
            for (int end = 0; end < 2; end++) {
                cur[(pre << 1) | end] = next[end];
                if (pre != 1) {
                    cur[(pre << 1) | end] = max(cur[(pre << 1) | end], arr[i] + next[2 + end]);
                }
            }
        }
        next[0] = cur[0];
        next[1] = cur[1];
        next[2] = cur[2];
        next[3] = cur[3];
    }
    return max(arr[0] + next[3], next[0]);
}

vector<int> randomArray(int n, int v) {
    vector<int> arr(n);
    srand(time(NULL));
    for (int i = 0; i < n; i++) {
        arr[i] = floor(v * ((double)rand() / RAND_MAX));
    }
    return arr;
}

int main() {
    int N = 16;
    int V = 100;
    int testTimes = 500;
    cout << "测试开始" << endl;
    for (int i = 0; i < testTimes; i++) {
        int n = rand() % N + 1;
        vector<int> arr = randomArray(n, V);
        int ans1 = max1(arr);
        int ans2 = max2(arr);
        int ans3 = max3(arr);
        if (ans1 != ans2 || ans1 != ans3) {
            cout << "出错了!" << i << endl;
            return 0;
        }
    }
    cout << "测试结束" << endl;
    return 0;
}

在这里插入图片描述

本作品采用《CC 协议》,转载必须注明作者和本文链接
微信公众号:福大大架构师每日一题。最新面试题,涉及golang,rust,mysql,redis,云原生,算法,分布式,网络,操作系统。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
482
粉丝
23
喜欢
38
收藏
22
排名:454
访问:2.0 万
私信
所有博文
社区赞助商