2695. Array Wrapper
Problem Description
The problem requires creating a class ArrayWrapper
that encapsulates an array of integers. This class should offer two specific behaviors:
-
When two instances of
ArrayWrapper
are added together using the+
operator, the result should be an integer representing the sum of all elements in both arrays wrapped by the instances. -
When the
String()
function is invoked on an instance ofArrayWrapper
, it should return a string representing the elements in the array, formatted as a comma-separated list enclosed within brackets.
To summarize, the ArrayWrapper
class needs to handle two types of operations: arithmetic addition and string conversion, going beyond the typical array functionality.
Intuition
To address the two requested features of the ArrayWrapper
class, we need to implement two key methods:
-
The
valueOf()
method: In JavaScript and TypeScript, thevalueOf()
method is called when an object is used in a context that expects a primitive value. By overriding this method, we can return the pre-calculated sum of the array's elements whenever the+
operator is used on an instance ofArrayWrapper
. -
The
toString()
method: This method is invoked when we attempt to convert an object to a string, such as when passing an object to theString()
function. Overriding thetoString()
method allows us to return the array elements as a formatted string, which matches the second behavior requirement.
The solution starts by initializing two instance variables in the constructor: nums
to store the array of integers and s
to store the sum of the array's elements. This sum is computed upfront using the reduce()
function to avoid repeated calculations during addition operations.
In the valueOf()
method, the sum s
is returned so that it can be used in arithmetic operations. When two ArrayWrapper
instances are added, this method is automatically called, and the sums of both instances are added together.
In the toString()
method, a string representation of the array is constructed using template literals, ensuring the format [1,2,3]
is achieved, where the actual numbers come from the stored nums
array.
By implementing these methods, ArrayWrapper
instances gain the ability to handle addition and string conversion in the desired manner.
Solution Approach
The implementation of the ArrayWrapper
class leverages the object-oriented features of TypeScript. Let's walk through the different parts of the implementation and dive into the algorithms, data structures, and patterns used:
-
Constructor: The
constructor
is a special method for creating and initializing objects created with a class. In this case, the constructor accepts an array of integers. Inside the constructor, we have the following steps:- The input array is stored in the private instance variable
nums
. The keywordprivate
ensures that this variable cannot be accessed directly from outside the class, encapsulating the data. - The sum of the array's elements is calculated using the
reduce()
function and stored in the private instance variables
. Thereduce()
function is a higher-order function that accumulates a value by applying a function to each element of an array, in this case, summing up their values.
- The input array is stored in the private instance variable
-
valueOf() Method: This method is overridden to fulfill the requirement of returning the sum of the array's elements when the
+
operator is used. There is no explicit call to this method in the code—the JavaScript (and by extension TypeScript) runtime calls it automatically when an object is used in a context that requires a primitive value (i.e., during arithmetic operations). -
toString() Method: This method is also overridden to meet the requirement of returning a string formatted as a comma-separated list enclosed within brackets whenever the
String()
function is used. Here, we are using template literals to create the desired string representation of the array.
The combination of these methods allows the ArrayWrapper
class to behave correctly for addition and string conversion operations. Once an instance of ArrayWrapper
is created, both methods work transparently to provide the functionality without further intervention. This is an example of how overriding built-in JavaScript methods can create custom behavior for operators and functions that normally work with primitive values.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's consider a small example to illustrate the solution approach for the ArrayWrapper
class. Suppose we initialize two instances of ArrayWrapper
with the arrays [1, 2, 3]
and [4, 5]
.
Here's how we could express it in code:
let arrayOne = new ArrayWrapper([1, 2, 3]); let arrayTwo = new ArrayWrapper([4, 5]);
Now, let's walk through the two behaviors as per the solution approach:
-
When we use the
+
operator on these instances:let sum = arrayOne + arrayTwo;
Internally, TypeScript will attempt to convert
arrayOne
andarrayTwo
to primitive values, triggering thevalueOf()
method on each instance. This will return the sum of the elements within eachArrayWrapper
.For our example,
arrayOne.valueOf()
will return6
(since 1+2+3 = 6), andarrayTwo.valueOf()
will return9
(since 4+5 = 9). The result assigned tosum
will be their collective sum:15
. -
When we pass an instance of
ArrayWrapper
to theString()
function:let str = String(arrayOne);
This triggers the
toString()
method onarrayOne
which constructs and returns a string in the format of a comma-separated list, encapsulated in brackets. ForarrayOne
, thetoString()
method will produce the string"[1,2,3]"
.
Now that we have a grasp of the process, let's translate this into the markdown template provided for documentation purposes:
Consider two instances of `ArrayWrapper`, one with the array `[1, 2, 3]` and the other with `[4, 5]`.
```typescript
let arrayOne = new ArrayWrapper([1, 2, 3]);
let arrayTwo = new ArrayWrapper([4, 5]);
Arithmetic Addition Using the +
Operator
When we calculate the sum of these two ArrayWrapper
instances:
let sum = arrayOne + arrayTwo;
arrayOne + arrayTwo
triggers the valueOf()
method on both arrayOne
and arrayTwo
. The sum for arrayOne
is 6
, while for arrayTwo
, it is 9
. These sums are then added to give us the total sum, 15
, which is the value of sum
.
String Conversion Using the String()
Function
When we convert arrayOne
to a string:
let str = String(arrayOne);
This invocation calls the toString()
method on arrayOne
, resulting in the string representation "[1,2,3]"
. This format is achieved by constructing the string with template literals, matching the array within brackets and separated by commas.
This walkthrough provides a clear example of the intended functionalities of the `ArrayWrapper` class: performing arithmetic addition and converting to a string representation.
Solution Implementation
1class ArrayWrapper:
2 # This will be used to store the next available id for a new array wrapper.
3 next_id = 0
4
5 # Initialize class-level dictionaries to store arrays and their sums.
6 arrays = {}
7 sums = {}
8
9 @classmethod
10 def init_array_wrapper(cls, nums):
11 """ Initialize a new array wrapper and store its data.
12
13 Args:
14 nums: A list of numbers to wrap.
15
16 Returns:
17 An identifier for the created array wrapper.
18 """
19 # Obtain the next ID and increment the ID counter.
20 array_id = cls.next_id
21 cls.next_id += 1
22
23 # Store the array and calculate the sum.
24 cls.arrays[array_id] = nums
25 cls.sums[array_id] = sum(nums)
26
27 return array_id
28
29 @classmethod
30 def sum_array_wrappers(cls, id1, id2):
31 """ Calculate the sum of two array wrappers.
32
33 Args:
34 id1: The identifier for the first array wrapper.
35 id2: The identifier for the second array wrapper.
36
37 Returns:
38 The sum of the values of both array wrappers.
39 """
40 # Retrieve sums for each id, defaulting to 0 if not found.
41 sum1 = cls.sums.get(id1, 0)
42 sum2 = cls.sums.get(id2, 0)
43
44 # Return the combined sum.
45 return sum1 + sum2
46
47 @classmethod
48 def array_wrapper_to_string(cls, array_id):
49 """ Get the string representation of an array wrapper.
50
51 Args:
52 array_id: The identifier for the array wrapper.
53
54 Returns:
55 The string representation of the array.
56 """
57 # Retrieve the array from storage.
58 nums = cls.arrays.get(array_id)
59
60 # Return the string representation.
61 if nums is not None:
62 return str(nums)
63 return ''
64
65
66# Example usage:
67
68# Initialize two array wrappers and store their identifiers.
69obj1_id = ArrayWrapper.init_array_wrapper([1, 2])
70obj2_id = ArrayWrapper.init_array_wrapper([3, 4])
71
72# Perform operations to get the sum of both arrays and their string representations.
73sum_of_arrays = ArrayWrapper.sum_array_wrappers(obj1_id, obj2_id) # Should return 10
74obj1_string = ArrayWrapper.array_wrapper_to_string(obj1_id) # Should return "[1, 2]"
75obj2_string = ArrayWrapper.array_wrapper_to_string(obj2_id) # Should return "[3, 4]"
76
1import java.util.HashMap;
2import java.util.Map;
3import java.util.stream.IntStream;
4
5// Class to manage array wrappers and their sums.
6class ArrayWrapperManager {
7
8 // Stores a mapping of array identifiers to their associated arrays.
9 private Map<Integer, int[]> arrays = new HashMap<>();
10 // Stores a mapping of array identifiers to their sums.
11 private Map<Integer, Integer> sums = new HashMap<>();
12 // Track the next array identifier to be used.
13 private int nextId = 0;
14
15 /**
16 * Initialize a new array wrapper and store its data.
17 * @param nums The array of numbers to wrap.
18 * @return The identifier for the created array wrapper.
19 */
20 public int initArrayWrapper(int[] nums) {
21 int id = nextId++;
22 arrays.put(id, nums);
23 sums.put(id, IntStream.of(nums).sum()); // Calculate sum using Java Streams
24 return id;
25 }
26
27 /**
28 * Calculates the sum of two array wrappers using their identifiers.
29 * @param id1 The identifier for the first array wrapper.
30 * @param id2 The identifier for the second array wrapper.
31 * @return The sum of the values of both array wrappers.
32 */
33 public int sumArrayWrappers(int id1, int id2) {
34 int sum1 = sums.getOrDefault(id1, 0); // Use getOrDefault to handle non-existing keys
35 int sum2 = sums.getOrDefault(id2, 0);
36 return sum1 + sum2;
37 }
38
39 /**
40 * Gets the string representation of an array wrapper.
41 * @param id The identifier for the array wrapper.
42 * @return The string representation of the array.
43 */
44 public String arrayWrapperToString(int id) {
45 if (!arrays.containsKey(id)) {
46 return "";
47 }
48 int[] nums = arrays.get(id);
49 // Convert array to String
50 return "[" + IntStream.of(nums)
51 .mapToObj(String::valueOf)
52 .reduce((a, b) -> a + "," + b)
53 .orElse("") + "]";
54 }
55}
56
57// Example usage of the ArrayWrapperManager class
58class ExampleUsage {
59 public static void main(String[] args) {
60 ArrayWrapperManager manager = new ArrayWrapperManager();
61
62 // Initialize two array wrappers and store their identifiers.
63 int obj1Id = manager.initArrayWrapper(new int[]{1, 2});
64 int obj2Id = manager.initArrayWrapper(new int[]{3, 4});
65
66 // Perform operations similarly to 'obj1 + obj2' and 'String(obj1)' from class example.
67 int sum = manager.sumArrayWrappers(obj1Id, obj2Id); // Should be 10
68 String obj1String = manager.arrayWrapperToString(obj1Id); // Should be "[1,2]"
69 String obj2String = manager.arrayWrapperToString(obj2Id); // Should be "[3,4]"
70
71 // Output the results
72 System.out.println("Sum of array wrappers: " + sum);
73 System.out.println("String representation of obj1: " + obj1String);
74 System.out.println("String representation of obj2: " + obj2String);
75 }
76}
77
1#include <unordered_map>
2#include <vector>
3#include <numeric>
4#include <string>
5#include <iostream>
6
7// Store a mapping of array identifiers to their associated arrays and sums.
8std::unordered_map<int, std::vector<int>> arrays;
9std::unordered_map<int, int> sums;
10
11// Track the next array identifier to be used.
12int nextId = 0;
13
14/**
15 * Initialize a new array wrapper and store its data globally.
16 * @param nums The vector of numbers to wrap.
17 * @returns The identifier for the created array wrapper.
18 */
19int initArrayWrapper(const std::vector<int>& nums) {
20 int id = nextId++;
21 arrays[id] = nums;
22 sums[id] = std::accumulate(nums.begin(), nums.end(), 0);
23 return id;
24}
25
26/**
27 * Calculates the sum of two array wrappers.
28 * @param id1 The identifier for the first array wrapper.
29 * @param id2 The identifier for the second array wrapper.
30 * @returns The sum of the values of both array wrappers.
31 */
32int sumArrayWrappers(int id1, int id2) {
33 int sum1 = sums.count(id1) ? sums[id1] : 0;
34 int sum2 = sums.count(id2) ? sums[id2] : 0;
35 return sum1 + sum2;
36}
37
38/**
39 * Gets the string representation of an array wrapper.
40 * @param id The identifier for the array wrapper.
41 * @returns The string representation of the array.
42 */
43std::string arrayWrapperToString(int id) {
44 if (arrays.find(id) == arrays.end()) {
45 return "";
46 }
47 const std::vector<int>& nums = arrays[id];
48 std::string res = "[";
49 for (size_t i = 0; i < nums.size(); ++i) {
50 res += std::to_string(nums[i]);
51 if (i < nums.size() - 1) res += ",";
52 }
53 res += "]";
54 return res;
55}
56
57// Main function to demonstrate usage of the functions.
58int main() {
59 // Initialize two array wrappers and store their identifiers.
60 int obj1Id = initArrayWrapper({1, 2});
61 int obj2Id = initArrayWrapper({3, 4});
62
63 // Perform operations similarly to the 'obj1 + obj2' and 'String(obj1)' examples.
64 int sum = sumArrayWrappers(obj1Id, obj2Id); // Should output 10
65 std::string obj1String = arrayWrapperToString(obj1Id); // Should output "[1,2]"
66 std::string obj2String = arrayWrapperToString(obj2Id); // Should output "[3,4]"
67
68 // Output to console for verification
69 std::cout << "Sum: " << sum << std::endl;
70 std::cout << "Obj1 String: " << obj1String << std::endl;
71 std::cout << "Obj2 String: " << obj2String << std::endl;
72
73 return 0;
74}
75
1// Store a mapping of array identifiers to their associated arrays and sums.
2const arrays = new Map<number, number[]>();
3const sums = new Map<number, number>();
4
5// Track the next array identifier to be used.
6let nextId = 0;
7
8/**
9 * Initialize a new array wrapper and store its data globally.
10 * @param nums The array of numbers to wrap.
11 * @returns The identifier for the created array wrapper.
12 */
13function initArrayWrapper(nums: number[]): number {
14 const id = nextId++;
15 arrays.set(id, nums);
16 sums.set(id, nums.reduce((a, b) => a + b, 0));
17 return id;
18}
19
20/**
21 * Calculates the sum of two array wrappers.
22 * @param id1 The identifier for the first array wrapper.
23 * @param id2 The identifier for the second array wrapper.
24 * @returns The sum of the values of both array wrappers.
25 */
26function sumArrayWrappers(id1: number, id2: number): number {
27 const sum1 = sums.get(id1) || 0;
28 const sum2 = sums.get(id2) || 0;
29 return sum1 + sum2;
30}
31
32/**
33 * Gets the string representation of an array wrapper.
34 * @param id The identifier for the array wrapper.
35 * @returns The string representation of the array.
36 */
37function arrayWrapperToString(id: number): string {
38 const nums = arrays.get(id);
39 if (!nums) {
40 return '';
41 }
42 return `[${nums}]`;
43}
44
45// Here's an example of how you would use these functions:
46
47// Initialize two array wrappers and store their identifiers.
48const obj1Id = initArrayWrapper([1, 2]);
49const obj2Id = initArrayWrapper([3, 4]);
50
51// Perform operations similarly to the 'obj1 + obj2' and 'String(obj1)' from the class example.
52const sum = sumArrayWrappers(obj1Id, obj2Id); // 10
53const obj1String = arrayWrapperToString(obj1Id); // "[1,2]"
54const obj2String = arrayWrapperToString(obj2Id); // "[3,4]"
55
Time and Space Complexity
Time Complexity
For the ArrayWrapper
constructor, we have the following operations and their complexities:
- Initializing
nums
with an array of lengthn
:O(1)
(assignment operation) - Calculating the sum of the
nums
array withreduce
:O(n)
wheren
is the number of elements in thenums
array.
Since these are the only two operations in the constructor and the reduce
function dominates the time complexity, the overall time complexity for the construction of an ArrayWrapper
instance is O(n)
.
The valueOf
method simply returns the sum (this.s
), which was pre-computed in the constructor. Thus, the time complexity for this operation is O(1)
.
The toString
method creates a string representation of the array. This operation goes over the array of length n
and constructs a string. The time complexity of this method is typically O(n)
because it is dependent on the length of the input array.
Space Complexity
- The space complexity for storing
nums
isO(n)
, wheren
is the length of the input array. - The sum
s
is just a single number, so it takesO(1)
.
Hence, the overall space complexity for an instance of the ArrayWrapper
class is O(n)
due to the storage of the nums
array.
Which data structure is used to implement priority queue?
Recommended Readings
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!