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. 如何用 ModelScope 实现 “AI 换脸” 视频

    前言 当下,视频内容火爆,带有争议性或反差大的换脸视频总能吸引人视线.虽然 AI 换脸在市面上已经流行了许久,相关制作工具或移动应用也是数不胜数.但是多数制作工具多数情况下不是会员就是收费,而且替换模 ...

  2. 聊聊 RocketMQ 名字服务

    NameServer 是专为 RocketMQ 设计的轻量级名字服务,它的源码非常精简,八个类 ,少于1000行代码. 这篇文章, 笔者会从基础概念.Broker发送心跳包.NameServer 维护 ...

  3. Java不能操作内存?Unsafe了解一下

    前言 C++可以动态的分类内存(但是得主动释放内存,避免内存泄漏),而java并不能这样,java的内存分配和垃圾回收统一由JVM管理,是不是java就不能操作内存呢?当然有其他办法可以操作内存,接下 ...

  4. IDA的使用-1

    IDA的使用-1 主要收集我自己需要掌握的或者以前不知道的 开始界面 重载文件 在我们逆向过程中被文件修改过,这个时候需要我们重载一下,比如说开发过程中加点代码之类的 下面是加载额外文件,这个文件和我 ...

  5. 《SQL与数据库基础》17. InnoDB引擎

    目录 InnoDB引擎 逻辑存储结构 架构 内存结构 磁盘结构 后台线程 事务原理 事务基础 redo log undo log MVCC 基本概念 隐式字段 undo log版本链 readView ...

  6. Linux 干货整理(持续更新)

    博客地址:https://www.cnblogs.com/zylyehuo/ 如果虚拟机开机没有 ip 怎么办 1.vim编辑网卡配置文件,修改如下参数 [root@s25linux tmp]# cd ...

  7. shell、python时间函数小结

    有时需要写一些定时任务脚本,简单总结一下,备忘. 1. 获取当前时间 python 在windows下精确到0.001秒,linux下时间精度为0.000001秒 >>> impor ...

  8. 使用 Sealos 一键部署高可用 MinIO,开启对象存储之旅

    大家好!今天这篇文章主要向大家介绍如何通过 Sealos 一键部署高可用 MinIO 集群. MinIO 对象存储是什么? 对象是二进制数据,例如图像.音频文件.电子表格甚至二进制可执行代码.对象的大 ...

  9. 每日一题:vue3自定义指令大全(呕心沥血所作,附可运行项目源码)

    1.VUE常用指令大全 本项目所有指令均为全局注册,使用时直接在组件中使用即可. 指令目录:src/directives 页面目录:src/views 具体可查看源码 1.1 权限指令 封装一个权限指 ...

  10. 使用Vue3+elementPlus的Tree组件实现一个拖拽文件夹管理

    目录 1.前言 2.分析 3. 实现 4.踩坑 4.1.拖拽辅助线的坑 4.2.数据的坑 4.3.限制拖拽 4.4.样式调整 1.前言 最近在做一个文件夹管理的功能,要实现一个树状的文件夹面板.里面包 ...