一言以蔽之:
dp 和分治 之间的区别就在于是否有重叠子问题 ,如果有那就应该dp 否则就应该分治。 当然如果可以每一步都产生最优解那么就不必dp了, 贪心算法就可以了. 而递归只是一种实现算法的方法.
例子
下面分别用 dp, dc(分治法), 贪心来做 leetcode 514. 自由之路
https://leetcode-cn.com/problems/freedom-trail/description/
golang 代码如下:
package main
import (
"fmt"
"math"
)
func main(){
//ring := "caotmcaataijjxi"
//key := "oatjiioicitatajtijciocjc"
//ring := "godding"
//key := "gd"
ring := "edcba"
key := "abcde"
ret1 := findRotateStepsDp(ring, key)
ret2 := findRotateStepsDc(ring, key)
ret3 := findRotateStepsGreedy(ring, key)
fmt.Println(ret1, ret2, ret3)
}
// ======================== 分治法 =================================
// time limit
// m:ring n:key
// m 的n次方
func findRotateStepsDc(ring string, key string) int {
l := len(key)
return findmin(ring, 0, key, 0, l)
}
// 从ring的s位置, key的i位置 所需要的最小值
func findmin(ring string, s int, key string, i int, l int)int{
if i >= l{
return 0
}
min := math.MaxInt32
temp := math.MaxInt32
for j := range ring{
if ring[j] == key[i]{
temp = calc(s, j, len(ring)) + findmin(ring, j, key , i + 1, l)
if temp < min{
min = temp
}
}
}
return min
}
// ======================== dp ===========================
// ac
func findRotateStepsDp(ring string, key string) int {
dp := make([][100]int, 100)
m := len(ring) - 1
n := len(key) - 1
for i := range key{
for j := range ring{
dp[i][j] = math.MaxInt32
if ring[j] == key[i]{
if i == 0{
dp[i][j] = calc0(0, j, m)
}else{
dp[i][j] = calcmin(dp, i-1 , j, m)
}
}
}
}
ret := math.MaxInt32
for i := 0; i <= m; i++{
ret = min(ret, dp[n][i])
}
return ret
}
// 要去dp(0, j) 位置 所需要的最小值
func calc0(i int, j int, m int)int{
ret := calc(j,i,m + 1)
return ret
}
// 要去 dp(i+1, j) 位置 所需的最小值
func calcmin(dp [][100]int, i int, j int, ringl int) int{
ret := math.MaxInt32
for k := 0; k <= ringl; k++{
ret = min(dp[i][k] + calc(j, k, ringl + 1), ret)
}
return ret
}
// ================================== greedy ===============================
// 不能ac 因为不满足贪心选择
func findRotateStepsGreedy(ring string, key string) int {
l := len(key)
return findRotateStepsGreedyUtil(ring, 0, key, 0, l)
}
func findRotateStepsGreedyUtil(ring string, start int, key string, i int, l int) int{
if i >= l {
return 0
}
count, nstart := findGreedy(ring, start, key, i)
return count + findRotateStepsGreedyUtil(ring, nstart, key, i+1, l)
}
func findGreedy(ring string, start int, key string, i int)(int, int){
c := math.MaxInt32
ctemp := math.MaxInt32
l := len(ring)
ret := start
for k := range ring{
if ring[k] == key[i]{
ctemp = min(calc(start, k, l), c)
if c != ctemp{
c = ctemp
ret = k
}
}
}
return c, ret
}
// ----------------- common func ----------------------
// a,b 最小值
func min(a int, b int) int{
if a < b{
return a
}
return b
}
// ring中 s 到mid 的最小距离
func calc(s int, e int, l int) int{
a := 0
b := 0
if s >= e{
a = s - e
b = l - a
return min(a, b) + 1
}else{
a = e - s
b = l - a
return min(a, b) + 1
}
}