You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
.We need to validate that brackets are properly opened and closed, following these rules:
199
+
.We need to validate that brackets are correctly opened and closed, following these rules:
200
200
- An opened bracket must be close by the same type.
201
201
- Open brackets mush be closed in the correct order.
202
202
203
-
This is a parsing problem, and usually, stacks are good candidates for them.
203
+
We are facing a parsing problem, and usually, stacks are good candidates for them.
204
204
205
205
*Algorithm*:
206
206
@@ -391,8 +391,8 @@ We can visit the tree using a Queue and keep track when a level ends, and the ne
391
391
392
392
Since during BFS, we dequeue one node and enqueue their two children (left and right), we might have two levels (current and next one). For this problem, we need to know what the last node on the current level is.
393
393
394
-
.There are several ways to solve this problem using BFS. Here are some ideas:
395
-
- *1 Queue + Sentinel node*: we can use a special character in the `Queue` like `'*'` or `null` to indicate the level's change. So, we would start something like this `const queue = new Queue([root, '*']);`.
394
+
.There are several ways to solve this problem by using BFS. Here are some ideas:
395
+
- *1 Queue + Sentinel node*: we can use a special character in the `Queue` like `'*'` or `null` to indicate a level change. So, we would start something like this `const queue = new Queue([root, '*']);`.
396
396
- *2 Queues*: using a "special" character might be seen as hacky, so you can also opt to keep two queues: one for the current level and another for the next level.
397
397
- *1 Queue + size tracking*: we track the Queue's `size` before the children are enqueued. That way, we know where the current level ends.
398
398
@@ -428,8 +428,164 @@ The complexity of any of the BFS methods or DFS is similar.
428
428
- Space: `O(n)`. For BFS, the worst-case space is given by the maximum *width*. That is when the binary tree is complete so that the last level would have `(n-1)/2` nodes, thus `O(n)`. For the DFS, the space complexity will be given by the tree's maximum *height*. In the worst-case, the binary tree is skewed to the right so that we will have an implicit call stack of size `n`.
This simple problem can have many solutions; let's explore some.
443
+
444
+
_Brute force_
445
+
446
+
One brute force approach could be doing two for loops. We sum two different numbers and check if they add up to the target. If yes, we return, and if not, we keep increasing the indices until we check every possible pair.
This approach's time complexity is `O(n^2)`, because we visit every number twice in the worst-case. While the space complexity is `O(1)`.
454
+
455
+
Can we trade space for time? Yes!
456
+
457
+
_Map_
458
+
459
+
Based on `nums[i] + nums[j] === target` we can say that `num[j] === target - nums[i]`. We can do one pass and check if we have seen any number equal to `target - nums[i]`. A map is perfect for this job. We could have a HashMap that maps `num` to `index`. Let's see the algorithms to make it work.
460
+
461
+
462
+
*Algorithm*:
463
+
464
+
* Visit every number once
465
+
** Calculate the complement `target - nums[i]`.
466
+
** If the complement exists, return its index and the current index.
467
+
** If not, save the complement and the index number.
This solution's time complexity is `O(n^3)` because of the 3 nested loops.
498
+
499
+
How can we do better? Notice that the last for loop, compute the sum repeatedly just to add one more.
500
+
Let's fix that!
501
+
502
+
_Cummulative Sum_
503
+
504
+
For this solution, instead of computing the sum from `i` to `j` all the time. We can calculate a cumulative sum. Every time we see a new number, we add it to the aggregate.
505
+
506
+
Since we want all possible subarray, We can increase `i` and get sum for each:
Notice that when the array has a 0, the cumulative sum has a repeated number. If you subtract those numbers, it will give you zero. In the same way, If you take two other ranges and subtract them (`sum[j] - sum[i]`), it will give you the sum of that range `sum(num[i]...num[j])`.
546
+
547
+
For instance, if we take the index `2` and `0` (with values 6 and 1) and susbtract them we get `6-1=5`. To verify we can add the array values from index 0 to 2, `sum([1, 2, 3]) === 5`.
548
+
549
+
With that intuition, we can use a Map to keep track of the aggregated sum and the number of times that sum.
550
+
551
+
*Algorithm*:
552
+
553
+
* Start sum at 0
554
+
* Visit every number on the array
555
+
** Compute the cumulative sum
556
+
** Check if `sum - k` exits; if so, it means that there's a subarray that adds up to k.
557
+
** Save the sum and the number of times that it has occurred.
You might wonder, what the map is initialized with `[0, 1]`. Consider this test case:
567
+
568
+
[source, javascript]
569
+
----
570
+
subarraySum([1], 1); // k = 1
571
+
----
572
+
573
+
The sum is 1, however `sum - k` is `0`. If it doesn't exist on the map, we will get the wrong answer since that number adds up to `k`. We need to add an initial case on the map: `map.set(0, 1)`. If `nums[i] - k = 0`, then that means that `nums[i] = k` and should be part of the solution.
574
+
575
+
*Complexity Analysis*:
576
+
577
+
- Time: `O(n)`. We visit every number once.
578
+
- Space: `O(n)`. The map size will be the same as the original array.
0 commit comments