动态规划、分治、贪心、递归

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kkx12138/article/details/81985394

一言以蔽之:
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
    }
}

猜你喜欢

转载自blog.csdn.net/kkx12138/article/details/81985394