dynamic programming
Recently, I have been swiping dynamic programming questions. It just so happens that leetcode China has a "learning plan" function, which assigns me the task of several questions every day.
Summarized a set of small templates for dynamic programming. Take the question "Jumping Game" as an example
defmodule Solution do
@spec can_jump(nums :: [integer]) :: boolean
def can_jump([x]), do: true
def can_jump([h | _] = nums) do
# 首先构造初始状态,由于 List 的访问时间是 O(n) 的,我们先将其转换为 Map
state = %{0 => h, nums: nums |> Enum.with_index() |> Enum.into(%{}, fn {v, k} -> {k, v} end)}
# 用一个 Agent 来保存状态,因为 elixir 里面一般不使用全局变量
Agent.start(fn -> state end, name: __MODULE__)
r = dp(length(nums) - 1)
# 结束后需要停止 Agent,否则状态会保存到下一个测试
Agent.stop(__MODULE__)
!!r
end
# dp 主逻辑
defp dp(i) do
find_and_store(i, fn %{nums: nums} -> nums[i] end, fn step ->
case dp(i - 1) do
false -> false
j ->
if j >= i do
max(j, i + step)
else
false
end
end
end)
end
# 通用函数,计算并存储最新状态。fget 函数是在 Agent 里执行,再返回结果。
# fdp 是状态转换的函数,其输入是 fget 的结果。
defp find_and_store(i, fget, fdp) do
case Agent.get(__MODULE__, fn m -> m[i] end) do
nil ->
x = Agent.get(__MODULE__, fget) |> fdp.()
Agent.update(__MODULE__, fn m -> Map.put(m, i, x) end)
x
x ->
x
end
end
end
Everyone may say, you are recursive like this, won't you burst the stack? In fact, I am also trembling, for fear that not using tail recursion will cause the stack to explode, but I have not encountered such a situation yet. Maybe the optimization of beam is very good.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。