[M模拟] lc380. O(1) 时间插入、删除和获取随机元素(模拟+数据结构+脑筋急转弯+数组快捷删除技巧+项目思考)

1. 题目来源

链接:380. O(1) 时间插入、删除和获取随机元素

题单:

  • 待补充

2. 题目解析

其实这个题目抽象一下的话在项目中也能出现,可能日常项目中没有算法基础的话,就很容易直接去进行新内存开辟、重复遍历等操作。尤其是在哈希表删除后,又需要进行一个相同概率返回的这个操作的时候。常见就有重新遍历哈希表到临时数组对象中,然后再依靠 rand 函数进行返回。

那么 O ( n ) O(n) O(n) 次的查询情况下每一个遍历都是 O ( n ) O(n) O(n) 的,那么整体的时间复杂度就是妥妥的 O ( n 2 ) O(n^2) O(n2) 的,在高并发场景下,这就是妥妥的项目坑点啊。

思路:

  • 构建一个哈希表、一个数组。哈希表用来存放 val 及数组中的该 val 的下标。数组用来存放全部元素, 便于最后通过 rand 函数进行相同概率的直接返回,避免遍历哈希表。
  • 主要是删除元素的时候,哈希表元素与数组元素怎么快速做到 O ( 1 ) O(1) O(1) 删除。
    • 我们只需要将数组最后一个元素与待删除元素调换位置,然后将最后一个元素 pop 出去就可以做到 O ( 1 ) O(1) O(1) 的删除了。
    • 同样上述的思想,在堆排序的向上调整、向下调整中也有用到。
    • 在如何 O ( 1 ) O(1) O(1) 删除单链表中的某一个节点元素的时候也有用到。

具体的看下如下代码即可,代码好理解,但如何运用到项目中去显著提高业务响应速度是值得我们去深思斟酌的。


  • 时间复杂度 O ( 1 ) O(1) O(1)
  • 空间复杂度 O ( n ) O(n) O(n)

type RandomizedSet struct {
    m map[int]int  // val--idx   存 val 值,及在 s 中的下标位置
    s []int        // val        存 val 值
}


func Constructor() RandomizedSet {
    r := RandomizedSet {
        s: make([]int, 0, 32),
        m: make(map[int]int),
    }

    return r
}


func (r *RandomizedSet) Insert(val int) bool {
    if _, ok := r.m[val]; ok {
        return false
    }
    r.m[val] = len(r.s)       // 新插入的 val 元素在 s 中的下标为总长度,及尾插
    r.s = append(r.s, val)
    return true
}


func (r *RandomizedSet) Remove(val int) bool {
    id, ok := r.m[val]
    if !ok {
        return false
    }

    last := len(r.m) - 1  // 拿到最后一个元素的下标
    r.s[id] = r.s[last]   // 在数组中,用最后一个元素值覆盖掉要删除的元素值,方便等会直接删除最后一个元素就行
    r.m[r.s[last]] = id   // 在哈希表中,重新建立索引关系,最后一个元素的哈希值应该是待删除元素的数组中的下标位置
    r.s = r.s[:last]      // 切片操作,删除最后一个元素即可
    delete(r.m, val)      // 哈希表操作,删除哈希表元素即可
    return true
}


func (r *RandomizedSet) GetRandom() int {
    return r.s[rand.Intn(len(r.s))]  // 随机化操作
}


/**
 * Your RandomizedSet object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Insert(val);
 * param_2 := obj.Remove(val);
 * param_3 := obj.GetRandom();
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

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

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

打赏作者

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

抵扣说明:

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

余额充值