Problem
You have a large array with most of the elements as zero.
Use a more space-efficient data structure, SparseArray, that implements the same interface:
init(arr, size)
: initialize with the original large array and size.set(i, val)
: updates index ati
withval
.get(i)
: gets the value at indexi
.
Examples
Example 1
Input: arr = [0, 1, 0, 0, 2, 0, 0, 3], size = 8
Output: values at indices by calling get(i) have the same values as the original array.
Input: sparseArray.set(4, 5)
Explanation: Updates the value at index 4 to 5 in the sparse array.
Input: sparseArray.get(4)
Output: 5
Explanation: Retrieves the updated value (5) at index 4.
Solution
Method 1 - Using Hashmap
A sparse array contains mostly zero values. Storing zeros explicitly in an array would be very space inefficient. Instead, we can use a dictionary (hashmap) to store only the non-zero elements. This way, we only use space proportional to the number of non-zero elements.
Approach
- Initialization:
init(arr, size)
will take the large array and its size, and store only non-zero elements in a dictionary where the key is the index and the value is the element. - Set Operation:
set(i, val)
will update the dictionary. Ifval
is non-zero, it adds or updates the entry in the dictionary. Ifval
is zero and the key exists in the dictionary, it removes the key. - Get Operation:
get(i)
will fetch the value from the dictionary. If the key does not exist, it returns zero.
Code
Java
public class Solution {
public static class SparseArray {
private Map<Integer, Integer> map;
private int size;
public void init(int[] arr, int size) {
this.size = size;
this.map = new HashMap<>();
for (int i = 0; i < size; i++) {
if (arr[i] != 0) {
map.put(i, arr[i]);
}
}
}
public void set(int i, int val) {
if (i >= size) {
throw new IndexOutOfBoundsException();
}
if (val == 0) {
map.remove(i);
} else {
map.put(i, val);
}
}
public int get(int i) {
if (i >= size) {
throw new IndexOutOfBoundsException();
}
return map.getOrDefault(i, 0);
}
}
}
Python
class Solution:
class SparseArray:
def __init__(self):
self.map: Dict[int, int] = {}
self.size: int = 0
def init(self, arr: List[int], size: int) -> None:
self.size = size
for i, val in enumerate(arr):
if val != 0:
self.map[i] = val
def set(self, i: int, val: int) -> None:
if i >= self.size:
raise IndexError("Index out of bounds")
if val == 0:
self.map.pop(i, None)
else:
self.map[i] = val
def get(self, i: int) -> int:
if i >= self.size:
raise IndexError("Index out of bounds")
return self.map.get(i, 0)
Complexity
- ⏰ Time complexity:
- Initialization (
init
):O(n)
wheren
is the size of the array. - Set Operation (
set
):O(1)
for insert/update/remove operations in the dictionary. - Get Operation (
get
):O(1)
for lookup in the dictionary.
- Initialization (
- 🧺 Space complexity:
O(m)
, wherem
is the number of non-zero elements in the array.