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;
}
總結
以上是生活随笔為你收集整理的2023-11-25:用go语言,给定一个数组arr,长度为n,表示n个格子的分数,并且这些格子首尾相连, 孩子不能选相邻的格子,不能回头选,不能选超过一圈, 但是孩子可以决定从任何位置开始选,也可以的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求一个古典个性签名!
- 下一篇: 手机银行的登录密码是什么