数据结构练习总结(1)

43 篇文章 1 订阅
30 篇文章 0 订阅

1.字典树

](https://img-blog.csdnimg.cn/dabb157db0574bab8c1d51f646180228.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAM-ePreW5sumlreeOi-ivt-aImA==,size_20,color_FFFFFF,t_70,g_se,x_16)

字典树(前缀树)是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。
向字典树中插入字符串word;
查询字符串word 是否已经插入到字典树中。
字典树的实现可以参考

https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode-ti500/

本题的思路和算法:

根据题意,WordDictionary 类需要支持添加单词和搜索单词的操作,可以使用字典树实现。

对于添加单词,将单词添加到字典树中即可。

对于搜索单词,从字典树的根结点开始搜索。由于待搜索的单词可能包含点号,因此在搜索过程中需要考虑点号的处理。对于当前字符是字母和点号的情况,分别按照如下方式处理:

如果当前字符是字母,则判断当前字符对应的子结点是否存在,如果子结点存在则移动到子结点,继续搜索下一个字符,如果子结点不存在则说明单词不存在,返回false;

如果当前字符是点号,由于点号可以表示任何字母,因此需要对当前结点的所有非空子结点继续搜索下一个字符。

重复上述步骤,直到返回false 或搜索完给定单词的最后一个字符。

如果搜索完给定的单词的最后一个字符,则当搜索到的最后一个结点的isEnd 为true 时,给定的单词存在。

特别地,当搜索到点号时,只要存在一个非空子结点可以搜索到给定的单词,即返回true。

代码实现如下:

type Trie struct {
    children [26]*Trie
    isEnd    bool
}

func Constructor() Trie {
    return Trie{}
}

func (t *Trie) Insert(word string) {
    node := t
    for _, ch := range word {
        ch -= 'a'
        if node.children[ch] == nil {
            node.children[ch] = &Trie{}
        }
        node = node.children[ch]
    }
    node.isEnd = true
}

func (t *Trie) SearchPrefix(prefix string) *Trie {
    node := t
    for _, ch := range prefix {
        ch -= 'a'
        if node.children[ch] == nil {
            return nil
        }
        node = node.children[ch]
    }
    return node
}

func (t *Trie) Search(word string) bool {
    node := t.SearchPrefix(word)
    return node != nil && node.isEnd
}

func (t *Trie) StartsWith(prefix string) bool {
    return t.SearchPrefix(prefix) != nil
}

2.数组操作

在这里插入图片描述

思路分析如下:
因为只需要找出让数组所有元素相等的最小操作次数,所以我们不需要考虑数组中各个元素的绝对大小,即不需要真正算出数组中所有元素相等时的元素值,只需要考虑数组中元素相对大小的变化即可。

因此,每次操作既可以理解为使n−1个元素增加 11,也可以理解使 11 个元素减少 11。显然,后者更利于我们的计算。

于是,要计算让数组中所有元素相等的操作数,我们只需要计算将数组中所有元素都减少到数组中元素最小值所需的操作数。
其中 nn 为数组 nums 的长度,min(nums)为数组 nums 中元素的最小值。

在实现中,为避免溢出,我们可以逐个累加每个元素与数组中元素最小值的差。

代码实现:

func minMoves(nums []int) int {
	min:=nums[0]
	sum:=0
	for _,num := range nums[1:]{
		if num<min{
			min = num
		}
	}
	for _,num:=range nums{
		sum += num-min
	}
	return sum
}

3.加一

在这里插入图片描述

当我们对数组digits 加一时,我们只需要关注digits 的末尾出现了多少个 99 即可。我们可以考虑如下的三种情况:

如果digits 的末尾没有 99,例如 [1, 2, 3][1,2,3],那么我们直接将末尾的数加一,得到 [1, 2, 4][1,2,4] 并返回;

如果digits 的末尾有若干个 99,例如 [1, 2, 3, 9, 9][1,2,3,9,9],那么我们只需要找出从末尾开始的第一个不为 99 的元素,即 33,将该元素加一,得到 [1, 2, 4, 9, 9][1,2,4,9,9]。随后将末尾的 99 全部置零,得到 [1, 2, 4, 0, 0][1,2,4,0,0] 并返回。

如果digits 的所有元素都是 99,例如 [9, 9, 9, 9, 9][9,9,9,9,9],那么答案为 [1, 0, 0, 0, 0, 0][1,0,0,0,0,0]。我们只需要构造一个长度比digits 多 11 的新数组,将首元素置为 11,其余元素置为 00 即可。

算法

们只需要对数组digits 进行一次逆序遍历,找出第一个不为 99 的元素,将其加一并将后续所有元素置零即可。如果digits 中所有的元素均为 99,那么对应着「思路」部分的第三种情况,我们需要返回一个新的数组。

func plusOne(digits []int) []int {
	digits[len(digits)-1]+=1
	for i:=len(digits)-1;i>0;i--{
		if digits[i]==10 {
			digits[i]=0
			digits[i-1]+=1
		}else {
			break
		}
	}
	if digits[0]==10 {
		digits[0]=0
		digits = append([]int{1},digits...)
	}
	return digits
}

大礼包

在这里插入图片描述
首先,我们过滤掉不需要计算的大礼包。

如果大礼包完全没有优惠(大礼包的价格大于等于原价购买大礼包内所有物品的价格),或者大礼包内不包含任何的物品,那么购买这些大礼包不可能使整体价格降低。因此,我们可以不考虑这些大礼包,并将它们过滤掉,以提高效率和方便编码。

因为题目规定了「不能购买超出购物清单指定数量的物品」,所以只要我们购买过滤后的大礼包,都一定可以令整体价格降低。

然后,我们计算满足购物清单所需花费的最低价格。
我们可以将所有可能的购物清单作为状态,并考虑这些状态之间相互转移的方法。

注意 :本文中涉及的题目与题解主要来自leetcode,只用于学习记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值