动态规划——贴纸拼词


/*
题目二
给定一个字符串str,给定一个字符串类型的数组arr
arr里的每一个字符串,代表一张贴纸,你可以把单个字符剪开使用,目的是拼出str来
每一种贴纸都可以使用任意张,重复的算2张,每一张贴纸都可以剪的非常的碎
返回需要至少多少张贴纸可以完成这个任务
例子: str = "babac", arr = {"ba","c","abcd"}
至少需要两张贴纸"ba"和 “abcd”, 因为使用这两张贴纸,把每一个字符单独剪开,含有2个a、2个b、1个c
是拼出str的,所以返回2

可以先排序
*/


/*
"baabk"
"aaccc"
"dfffd"

[2200...1]       // n个26长度数组
 0123...'k'-'a'
 abcd   k

 */



//leetcode https://leetcode-cn.com/problems/stickers-to-spell-word/
func minStickers1(stickers []string, target string) int { //target 剩余的字符串
	n := len(stickers)
	mp := make([][]int,n)  // 代表所有贴纸
	for k := range mp {
		mp[k] = make([]int,26)
	}
	dp := map[string]int{}   //傻缓存
	for i := 0; i < n; i++ {
		for _, char := range stickers[i] {  // 生成每一张的贴纸的词频统计
			mp[i][char-'a']++
		}
	}
	dp[""] = 0


	return processMinStickers1(&dp,mp,target)
}
// 若返回值是-1,表示mp中的贴纸怎么都无法搞定剩余的rest字符串的
func processMinStickers1(dp *map[string]int,mp [][]int,rest string) int {
	if _,ok := (*dp)[rest]; ok {
		return (*dp)[rest]
	}

	//一下就是正式的递归调用过程
	ans := math.MaxInt        // 搞定rest 使用最少的贴纸数量
	n :=  len(mp)             // n种贴纸
	tmap := make([]int,26)    // rest 转换成词频类型 tmp 替代rest
	for _, char := range rest {  // 用魔法去对抗魔法
		tmap[char-'a']++
	}


	for i := 0; i < n ; i++ {
		if mp[i][rest[0]-'a'] == 0 { // "aaaabbbbbcccc" 字符串,剩余字符串是"xyz"的话就跑不完了,小贪心
			continue                 // 贴纸中必须包含target字符中的一个
		}
		/*
		不加上边这句会栈溢出
		runtime: goroutine stack exceeds 1000000000-byte limit
		runtime: sp=0xc020181388 stack=[0xc020180000, 0xc040180000]
		fatal error: stack overflow
		 */

		sb := bytes.Buffer{}

		// i 贴纸, j 枚举a~z 字符
		for j := 0; j < 26; j++ {
			if tmap[j] > 0 {
				for k := 0; k < Max(0, tmap[j]-mp[i][j]); k++ {
					sb.WriteByte(byte('a'+j))
				}
			}
		}
		s := sb.String() // 剩下的字符,减法操作
		tmp := processMinStickers1(dp,mp,s)
		if tmp != -1 {
			ans = Min(ans,1 + tmp)
		}
	}

	if ans == math.MaxInt {
		(*dp)[rest] = -1
	}else {
		(*dp)[rest] = ans
	}
	return (*dp)[rest]
}
// 可能性太多了,无法改成精细化结构的动态规划,虽然有重复解




/*
方法二,略
"aaaabbbccc"
"aa"
"bb"
"cc"
每一轮枚举每一张贴纸的张数

设计递归的原则:可变参数尽量的少,以此换取缓存的命中率
 */







func TestMinStickers1(t *testing.T)  {
	arr := []string{"aaaa","bbaa","ccddd"}
	str := "abcccccdddddbbbaaaaa"
	t.Log(minStickers1(arr,str))

	t.Logf("%x",math.MaxInt)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值