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;
}

2023-11-25:用go语言,给定一个数组arr,长度为n,表示n个格子的分数,并且这些格子首尾相连, 孩子不能选相邻的格子,不能回头选,不能选超过一圈, 但是孩子可以决定从任何位置开始选,也可以的更多相关文章

  1. 算法题——给定一个数组 arr,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

    参考自:https://blog.csdn.net/qq_38200548/article/details/80688630 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] ...

  2. [java大数据面试] 2018年4月百度面试经过+三面算法题:给定一个数组,求和为定值的所有组合.

    给定一个数组,求和为定值的所有组合, 这道算法题在leetcode应该算是中等偏下难度, 对三到五年工作经验主要做业务开发的同学来说, 一般较难的也就是这种程度了. 简述经过: 不算hr面,总计四面, ...

  3. 【IT笔试面试题整理】给定一个数组a[N]构造数组b [N]

    [来源]:腾讯2013实习生笔试   给定一个数组a[N],我们希望构造数组b [N],其中b[j]=a[0]*a[1]-a[N-1] / a[j])空间复杂度和O(n)的时间复杂度:除遍历计数器与a ...

  4. 给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度为O(N),且要求不能用非基于比较的排序

    题目: 给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度为O(N),且要求不能用非基于比较的排序 public static int maxGap(int nums[]) { if ( ...

  5. 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润. 注意你不能在买入股票前卖出股票. 示例 ...

  6. delphi 判断一个数组的长度用 Length 还是 SizeOf ?

    判断一个数组的长度用 Length 还是 SizeOf ?最近发现一些代码, 甚至有一些专家代码, 在遍历数组时所用的数组长度竟然是 SizeOf(arr); 这不合适! 如果是一维数组.且元素大小是 ...

  7. 刷题3:给定一个数组 nums,判断 nums 中是否存在三个下标 a,b,c数相加等于targe且a,b,c不相等

    题目: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,下标 ,a ,b , c 对应数相加等于 targe 找出所有满足条件且不重复的三元组下标 解析: ...

  8. java 一个数组的长度

    package java03; /* *如何获取数组长度 : * 格式: * 数组名称.length * * 这会得到一个int数字,代表数组的长度 * * 数组一旦创建,程序运行期间,长度不可改变 ...

  9. 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

    示例 1: 输入: [1,2,3,4,5,6,7] 和 k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右旋转 1 步: [7,1,2,3,4,5,6] 向右旋转 2 步: [6,7,1 ...

  10. 给定一个数组,求如果排序后,相邻两个元素的最大差值,要求时间复杂度为O(N)

    第一种方法: 计数排序后,然后找出两两之间的最大差值 计数排序的时间复杂度是O(N) public class CountSort { public static void main(String[] ...

随机推荐

  1. js 关于 replace 取值、替换第几个匹配项(两种方式:正则、普通字符串操作)

    〇.前言 在日常开发中,经常遇到针对字符串的替换.截取,知识点比较碎容易混淆,特此总结一下,仅供参考. 一.替换第一个匹配项 字符串替换 let strtest = "0123测试repla ...

  2. 使用kafka自带脚本进行压力测试

    前言 kafka官方自带压力测试脚本: 消费者压力测试:kafka-consumer-perf-test.sh 生产者压力测试:kafka-producer-perf-test.sh 测试节点: 17 ...

  3. 社区活动 | “中文 AI 微小说大赛”正式开启报名!

    ️ 我们要求每位参赛选手以 LLM (大语言模型)为工具,将 AI 的能力与选手的创作才华相结合,创造出引人入胜.感人至深或充满疯狂的微小说! 无论你是首次接触 AI 工具还是资深的从业者,我们期待在 ...

  4. mysql拓展

    事务定义 就是将一组SQL语句放在同一批次内去执行 如果一个sql语句出错,则改批次内的所有sql都将被取消执行 (1)原子性 一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作, ...

  5. 【技术积累】Linux中的命令行【理论篇】【七】

    atrm命令 命令介绍 atrm命令是Linux系统中的一个命令行工具,用于取消或删除已经安排的at命令.at命令是一种用于在指定时间执行一次性任务的工具. 命令说明 atrm命令的语法如下: atr ...

  6. 使用 docker 打包构建部署 Vue 项目,一劳永逸解决node-sass安装问题

    文章源于 Jenkins 构建 Vue 项目失败,然后就把 node_modules 删了重新构建发现 node-sass 安装不上了,折腾一天终于可以稳定构建了. 犹记得从学 node 的第一天,就 ...

  7. 三维模型OSGB格式轻量化纹理压缩关键技术分析

    三维模型OSGB格式轻量化纹理压缩关键技术分析 在三维模型应用中,纹理是一个十分重要的因素,可以使得模型更加真实.精细.随着移动设备和网络传输速度的限制,纹理数据也需要进行轻量化处理,而OSGB格式纹 ...

  8. DesignPattern-part2

    title: "modern C++ DesignPattern-Part2" date: 2018-04-10T19:08:49+08:00 lastmod: 2018-04-1 ...

  9. SQL注入——搜索型

    SQL注入-搜索型 搜索型注入-原理介绍 一些网站为了方便用户查找网站的资源,都对用户提供了搜索的功能,因为是搜索功能,往往是程序员在编写代码时都忽略了对其变量(参数)的过滤,而且这样的漏洞在国内的系 ...

  10. LeetCode297:hard级别中最简单的存在,java版,用时击败98%,内存击败百分之九十九

    本篇概览 因为欣宸个人水平有限,在刷题时一直不敢面对hard级别的题目,生怕出现一杯茶一包烟,一道hard做一天的窘境 这种恐惧心理一直在,直到遇见了它:LeetCode297,建议不敢做hard题的 ...