LC每日一题|20240426 - 1146. 快照数组

35 阅读1分钟

LC每日一题|20240426 - 1146. 快照数组

实现支持下列接口的「快照数组」- SnapshotArray:

  • SnapshotArray(int length) - 初始化一个与指定长度相等的 类数组 的数据结构。初始时,每个元素都等于 0
  • void set(index, val) - 会将指定索引 index 处的元素设置为 val
  • int snap() - 获取该数组的快照,并返回快照的编号 snap_id(快照号是调用 snap() 的总次数减去 1)。
  • int get(index, snap_id) - 根据指定的 snap_id 选择快照,并返回该快照指定索引 index 的值。

提示:

  • 1 <= length <= 50000
  • 题目最多进行50000setsnap,和 get的调用 。
  • 0 <= index < length
  • 0 <= snap_id < 我们调用 snap() 的总次数
  • 0 <= val <= 10^9

题目等级:Medium

解题思路

看这个数据量暴力是肯定没戏的。

我们可以统计在每次snap中有哪些位置发生了改变,并以此维护一个记录每个位置改变的时刻与值的表。

对于每次查询,我们只需要在对应位置的表中二分找到小于等于目标snapId所对应的值返回即可。

AC代码

class SnapshotArray(private val length: Int) {

    val arr = IntArray(length)
    val map = Array<ArrayList<IntArray>>(length) { arrayListOf() }
    val cur = HashMap<Int, Int>()
    var snapId = -1

    fun set(index: Int, `val`: Int) {
        cur[index] = `val`
    }

    fun snap(): Int {
        snapId++
        cur.forEach {
            map[it.key].add(intArrayOf(snapId, it.value!!))
        }
        cur.clear()
        return snapId
    }

    fun get(index: Int, snap_id: Int): Int {
        if (map[index].isEmpty() || snap_id < map[index][0][0]) return 0
        var start = 0
        var end = map[index].size - 1
        while (start < end) {
            val mid = (start + end + 1) / 2
            when {
                snap_id < map[index][mid][0] -> end = mid - 1
                snap_id >= map[index][mid][0] -> start = mid
            }
        }      
        return map[index][start][1]
    }
}

/**
 * Your SnapshotArray object will be instantiated and called as such:
 * var obj = SnapshotArray(length)
 * obj.set(index,`val`)
 * var param_2 = obj.snap()
 * var param_3 = obj.get(index,snap_id)
 */

碎碎念

我恨二分!!!