Gemini永久会员 Go 实现动态规划

Go 实现动态规划

动态规划(Dynamic Programming, DP)是一种分阶段解决问题的方法,适用于具有重叠子问题和最优子结构性质的问题。下面我将展示几个用Go语言实现的经典动态规划示例。

1. 斐波那契数列

go 复制代码
package main

import "fmt"

// 递归方法(非DP,效率低)
func fibRecursive(n int) int {
    if n <= 1 {
        return n
    }
    return fibRecursive(n-1) + fibRecursive(n-2)
}

// 记忆化搜索(自顶向下DP)
func fibMemo(n int, memo map[int]int) int {
    if n <= 1 {
        return n
    }
    if val, ok := memo[n]; ok {
        return val
    }
    memo[n] = fibMemo(n-1, memo) + fibMemo(n-2, memo)
    return memo[n]
}

// 动态规划(自底向上)
func fibDP(n int) int {
    if n <= 1 {
        return n
    }
    dp := make([]int, n+1)
    dp[0], dp[1] = 0, 1
    for i := 2; i <= n; i++ {
        dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
}

// 优化空间版本的DP
func fibDPSpaceOptimized(n int) int {
    if n <= 1 {
        return n
    }
    prev, curr := 0, 1
    for i := 2; i <= n; i++ {
        prev, curr = curr, prev+curr
    }
    return curr
}

func main() {
    n := 10
    fmt.Println("递归:", fibRecursive(n))
    
    memo := make(map[int]int)
    fmt.Println("记忆化:", fibMemo(n, memo))
    
    fmt.Println("DP:", fibDP(n))
    fmt.Println("DP(空间优化):", fibDPSpaceOptimized(n))
}

2. 0-1背包问题

go 复制代码
package main

import "fmt"

func knapsack(weights []int, values []int, capacity int) int {
    n := len(weights)
    dp := make([][]int, n+1)
    for i := range dp {
        dp[i] = make([]int, capacity+1)
    }

    for i := 1; i <= n; i++ {
        for w := 1; w <= capacity; w++ {
            if weights[i-1] <= w {
                dp[i][w] = max(values[i-1]+dp[i-1][w-weights[i-1]], dp[i-1][w])
            } else {
                dp[i][w] = dp[i-1][w]
            }
        }
    }

    return dp[n][capacity]
}

// 空间优化版本
func knapsackOptimized(weights []int, values []int, capacity int) int {
    n := len(weights)
    dp := make([]int, capacity+1)

    for i := 0; i < n; i++ {
        for w := capacity; w >= weights[i]; w-- {
            dp[w] = max(dp[w], values[i]+dp[w-weights[i]])
        }
    }

    return dp[capacity]
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func main() {
    weights := []int{2, 3, 4, 5}
    values := []int{3, 4, 5, 6}
    capacity := 8

    fmt.Println("背包最大价值:", knapsack(weights, values, capacity))
    fmt.Println("背包最大价值(空间优化):", knapsackOptimized(weights, values, capacity))
}

3. 最长公共子序列(LCS)

go 复制代码
package main

import "fmt"

func longestCommonSubsequence(text1 string, text2 string) int {
    m, n := len(text1), len(text2)
    dp := make([][]int, m+1)
    for i := range dp {
        dp[i] = make([]int, n+1)
    }

    for i := 1; i <= m; i++ {
        for j := 1; j <= n; j++ {
            if text1[i-1] == text2[j-1] {
                dp[i][j] = dp[i-1][j-1] + 1
            } else {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
            }
        }
    }

    return dp[m][n]
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func main() {
    text1 := "abcde"
    text2 := "ace"
    fmt.Println("LCS长度:", longestCommonSubsequence(text1, text2))
}

4. 硬币找零问题

go 复制代码
package main

import (
    "fmt"
    "math"
)

func coinChange(coins []int, amount int) int {
    dp := make([]int, amount+1)
    for i := range dp {
        dp[i] = amount + 1 // 初始化为一个不可能的大值
    }
    dp[0] = 0

    for i := 1; i <= amount; i++ {
        for _, coin := range coins {
            if coin <= i {
                dp[i] = min(dp[i], dp[i-coin]+1)
            }
        }
    }

    if dp[amount] > amount {
        return -1
    }
    return dp[amount]
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

func main() {
    coins := []int{1, 2, 5}
    amount := 11
    fmt.Println("最少硬币数:", coinChange(coins, amount))
}

动态规划实现要点

  1. 定义状态:明确DP数组或变量的含义
  2. 确定状态转移方程:找出如何从之前的状态计算当前状态
  3. 初始化边界条件:设置初始状态的值
  4. 确定计算顺序:是自顶向下还是自底向上
  5. 考虑空间优化:有时可以降低空间复杂度

Go语言实现动态规划时,通常使用切片(slice)来表示DP数组,注意初始化大小和边界条件。对于需要优化的场景,可以考虑使用滚动数组等技术减少空间使用。

希望这些示例能帮助你理解如何在Go中实现动态规划算法!

相关推荐
秋饼6 小时前
【手撕 @EnableAsync:揭秘 SpringBoot @Enable 注解的魔法开关】
java·spring boot·后端
m0_603888716 小时前
Scaling Trends for Multi-Hop Contextual Reasoning in Mid-Scale Language Models
人工智能·算法·ai·语言模型·论文速览
Xの哲學6 小时前
Linux io_uring 深度剖析: 重新定义高性能I/O的架构革命
linux·服务器·网络·算法·边缘计算
IT_陈寒6 小时前
Python 3.12 新特性实战:这5个改进让我的开发效率提升40%
前端·人工智能·后端
利兄的视界6 小时前
一步到位:M4 芯片 Mac 安装 PostgreSQL 16 并适配 pgvector 教程
后端·postgresql
GZKING6 小时前
ThinkPHP 8 报错"think\model\pivot" not found
后端
comli_cn6 小时前
残差链接(Residual Connection)
人工智能·算法
Aaron15886 小时前
基于VU13P在人工智能高速接口传输上的应用浅析
人工智能·算法·fpga开发·硬件架构·信息与通信·信号处理·基带工程
予枫的编程笔记6 小时前
【论文解读】DLF:以语言为核心的多模态情感分析新范式 (AAAI 2025)
人工智能·python·算法·机器学习
im_AMBER6 小时前
Leetcode 99 删除排序链表中的重复元素 | 合并两个链表
数据结构·笔记·学习·算法·leetcode·链表