leetcode icon indicating copy to clipboard operation
leetcode copied to clipboard

Day 7 | 3/20/20

Open tech-cow opened this issue 5 years ago • 1 comments

  • [ ] 1146. Snapshot Array

tech-cow avatar Mar 20 '20 16:03 tech-cow

1146. Snapshot Array

Brute Force | Memory Limit Exceeded

Memory usage needs to be more efficient. In this code snippet, too many unused 0 element were stored in the dictionary value. Instead, only store used index and value. A nested dictionary does the trick

class SnapshotArray(object):

    def __init__(self, length):
        self.length = length
        self.arr = [0] * self.length
        self.snap_id = -1
        self.dic = {}
        

    def set(self, index, val):
        if index >= 0 and index < len(self.arr):
            self.arr[index] = val

    def snap(self):
        self.snap_id += 1
        self.dic[self.snap_id] = self.arr[:]
        return self.snap_id
        

    def get(self, index, snap_id):
        if snap_id in self.dic:
            return self.dic[snap_id][index]

Hashmap + Deepcopy

This code snippet still duplicates previous snap_array, thus create redundency in elements. for example: image Instead of making a copy to all elements, we only need to make new copies of the elements that has been modified. For the remaining unchanged elements, we can query them by a backward while loop, which increase the time complexity back to O(N)

However the time complexity is GREAT

set() O(1) set() O(1) get() O(1)

from collections import defaultdict
class SnapshotArray(object):
    def __init__(self, length):
        self.dic = defaultdict(dict)
        self.snap_id = 0
        
        
    def set(self, index, val):
        self.dic[self.snap_id][index] = val
        

    def snap(self):
        self.snap_id += 1
        self.dic[self.snap_id] = self.dic[self.snap_id - 1].copy()
        return self.snap_id -1
        

    def get(self, index, snap_id):
        if index in self.dic[snap_id]:
            return self.dic[snap_id][index]
        else:
            return 0

Backward While Loop

We can make this search faster by replacing linear query with a binary search

from collections import defaultdict
class SnapshotArray:
    def __init__(self, length: int):
        self.snap_id = 0
        self.history = defaultdict(dict)
    
    def set(self, index: int, val: int) -> None:
        self.history[self.snap_id][index] = val
    
    def snap(self) -> int:
        self.snap_id += 1
        return self.snap_id - 1
    
    def get(self, index: int, snap_id: int) -> int:
        copy_id = snap_id
        while copy_id > 0 and index not in self.history[copy_id]:
            copy_id -= 1
        if index in self.history[copy_id]:
            return self.history[copy_id][index]
        return 0

Backward Binary Search

Code Snippet from @lee215

    def __init__(self, n):
        self.A = [[[-1, 0]] for _ in xrange(n)]
        self.snap_id = 0

    def set(self, index, val):
        self.A[index].append([self.snap_id, val])

    def snap(self):
        self.snap_id += 1
        return self.snap_id - 1

    def get(self, index, snap_id):
        i = bisect.bisect(self.A[index], [snap_id + 1]) - 1
        return self.A[index][i][1]

tech-cow avatar Mar 20 '20 16:03 tech-cow