```
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
```

When i attempted the problem on my own, I figured I could simply find the sum of all odd indicies and the sum of all even indicies and then compare them. Obviously this logic does not actually work since a robber could theoretically rob house 0 and house 3 if the input array were to look something like `[5,1,1,5]`

. He would get 10 by robbing homes 0 and 3 but he would get the same amount if he robbed the evens vs the odds. So this type of logic can be ruled out.

To approach the correct solution, we can make a decision tree by checking the first two homes. If the robber robs the first home, he must skip the second home and then either robs house 3 or 4. If he robs the second home, he cannot rob house 3 and can only rob house 4. A decision tree could look something like this:

```
start
/ \
1 2
/ \ \
3 1 1
```

It is best to break up the problem into subproblems. If we start at the first house, we skip the second house, and now our “subproblem” are homes 3 and 4. If we start at the second house, our “subproblem” is now just house 4. Programatically, this could look something like:

```
max(nums[0] + rob[2:n], max[1:n])
```

We can start at the beginning of the array and compute the most we could rob at each element.

- Starting at at house 0, the most we can rob is
`1`

since that is the only house. - Considering houses 0 and 1, we look at the maximum in the array (at that point). The only values we’ve encountered are 1 and 2. So
`2`

is our answer.

If we only consider houses 0, 1, and 2, we can either:

- Rob houses 0 and 2 ->
`1 + 3 = 4`

- Rob house 1 ->
`2`

- Compare which one is greater

When we include all the homes:

- If we decide to rob house 3, we can either pick the max of house 0 or 1, which we calculated before, and also rob house 3.
- If we don’t decide to rob house 3, we can pick the maximum amount from houses 0-2, which we also already calculated before.
- We can now do a simple comparison:
- If we pick the first option, the most we could rob is max(house0, house1) + house3 = max(1,2) + 1 = 3
- If we pick the second option, the most we can rob is 4.
- 3 < 4, so 4 is our answer

When we are figuring out how much we can rob at a house, we can look at the previous two results in the array.

`| 1 2 | ~~3~~ | 1 |`

OR

`| 1 2 3 | ~~1~~`

When we were at house 3, we were essentially comparing the max we could have gotten at house 2 vs the max we could have gotten at house 1.

Based on this intuition, we don’t need a separate array to store the maximums. We can use variables to store house 0 and 1 and a for loop which would start computing at house 2. We set the two variables, which I will call `house0`

and `house1`

to 0. The for loop would loop through the `nums`

array and store the maximum amount at that particular index. Since we start the computing at house 2, the most we can steal is the max of house 0 and n, the value at that index, which in our case is 2 OR house 1. Programatically it would look something like this:

```
max(n + house0, house1)
```

At this point, our array might look something like this:

`[house0, house1, n]`

As we include more values, the array might start looking like this:

`[house0, house1, n, n+1, n+2, ...]`

We also need to update the values of house0 and house1.

- The value at house0 is now set to the value at house1
- The value at house1 is now set to the amount we calculated in the previous step. That value should be stored in some kind of temp variable.

**Time Complexity**: O(n) because we used a single for loop to traverse the entire nums array

**Space Complexity**: O(1) because we are only using variables to store the maximums. A separate array is not required.

The code to the problem can be found here and I hope you enjoyed this writeup.

]]>```
A message containing letters from A-Z can be encoded into numbers using the following mapping:
'A' -> "1"
'B' -> "2"
...
'Z' -> "26"
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).
```

When approaching the problem, it’s important to break up the problem into smaller sub-problems, which is why it’s a classic Dynamic Programming problem. In this case, we will break up the string into smaller substrings, which can correspond to a specific number. Let’s use the given example where `s=12`

. We analyze the first character, `1`

. We know that `1`

corresponds to `A`

in the alphabet. However, we also know that `1`

could also be the start of a two digit number from `10-19`

. Same goes for `2`

which could correspond to the start of a two digit number from `20-26`

. If a number is from `3-9`

we know that it can only represent a single digit and therefore a single character. But for 1 and 2, we need to check the next digit before concluding what the letter might be.

We can also represent this as a decision tree, where we start at the beginning and draw arrows depending on what “decision” to take next. Here is a rudimentary example of using `s=12`

:

```
"12"
/ \
"1" "12"
/
"2"
```

We know that the first digit `1`

coresponds to `"A"`

and when we next the next digit `2`

that corresponds to the letter `"B"`

. However, as previously mentioned, since we have a 1 and 2, we can correspond the 12 back to L. So in this scenario, there are two ways to decode this string. (i know the answer was posted in the problem but i wanted to go through it).

The way I approached the problem was to create a list which holds the possible number of “ways” at each character in the string. If the string has length 0 there is only one way to decode it. If a string has length of 1 there is only 1 way to decode it, unless that character is a 0, in which there are 0 ways to decode it. For strings where the length is 2 or more, we loop through the string, and check the digit before it and two digits before it. If we check the two digits before it and those two digits correspond to a number between 10 and 26 we have found a character between J and Z. If we check the digit before it, we can correspond it to a letter between A and I.

Keep in mind that we do not need to print out all possible ways, just the total number of ways. So if the digit before it is greater than 1 we know that the total number of ways at that index is one more than the index before it. If our input string was `"789"`

, there is one way to decode the first character, one more way to decode the string at the second character (2), and one more way to decode the string at the third character (3). So our final answer is 3.

Let’s say our input string was `"121"`

. There is one way to decode the string at the first index, but when we hit the second index, there are two ways to decode it because we can either have 1 and 2 separately or 12. At the third index, there are also two more ways to decode it because we can treat the 2 and 1 separately or 21 as a single character. So we would go from 1 to 3 to 5, which is our final answer.

After traversing the string, you would return the value at the final index. This means you would initialize a list with 0 times the number of characters in the input string. For example:

```
dp = [0] * (len(s) + 1)
return dp[len(s)]
```

could be a way to represent that with code.

**Time Complexity**: O(n) because you traverse the input string once.

**Space Complexity**: O(n) because you initialize a separate list with the same number of elements as the number of characters in the input string.

The code to the problem can be found here and I hope you enjoyed this writeup.

]]>```
Given a string s, find the length of the longest substring without repeating characters.
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
```

The brute force approach to solving this problem would involve a nested for-loop by checking every single possible combination of characters. If two adjacent characters are the same, it means that the given substring we are looking at contains a repeating character pattern, for which we would not include. The worst case time complexity would be `O(n^2)`

since we have the nested for-loop structure. This approach can be dramatically improved to `O(n)`

by utilizing a common algorithm for solving many array and string questions: the Sliding Window.

For this problem, we will utilize a left and right pointer and our window will be the range from left to right. We also need some kind of data structure to store unique elements. The best one would be a set. This set will store the characters in our sliding window and will add or remove depending on if we have already seen the current string.

To solve the problem I will use the example that Leetcode gives us. We will initialize our left and right pointers to 0, which is the first character in the string, `a`

. Since our set is empty, we can add it there. Since we have not found any duplicates yet, we will only slide the right pointer by incrementing by one. The next character is `b`

. Since we don’t have a `b`

in our set, we will add it to our set, and then slide the right pointer again by one. The next character is `c`

. Since we haven’t seeen a `c`

in our set just yet, we slide right again.

Now, the next character is an `a`

. However, we already have an `a`

in our set. So we need to remove that first `a`

from our set, which is esesntialy the left pointer. After we remove the `a`

, we slide BOTH the left and right pointers. Our window (set) now contains `b`

, `c`

, and `a`

. The next character is `b`

, which already exists in our set. So we do the same thing for the previous character.

If you notice, we keep adding the left and right characters to our string and increment the right pointer by 1. However, if the character at the right pointer already exists in our set, we will remove the character at the left pointer and increment our left pointer by 1.

Another important thing to mention is that we need a variable to store the length of the existing substring and compare it to the length of the window, which can be calculated by doing `r - l`

. Once our right pointer hits the end of the string, we can stop iterating through the string.

**Time Complexity**: We are guaranteed to do a single traversal of the string. So our time complexity is `O(n)`

.

**Space Complexity**: At worst, we will need to store every single character in our set if every single character in the string is unique. So the space complexity is `O(n)`

.

The code to the problem can be found here and I hope you enjoyed this writeup.

]]>```
Given an array of strings strs, group the anagrams together. You can return the answer in any order.
For example, if strs = ["eat","tea","tan","ate","nat","bat"], then we want to return [["bat"],["nat","tan"],["ate","eat","tea"]]
```

This is a little tricky at first but after some thinking, you can solve it using a dictionary/map.

Before jumping into the problem, it’s important to understand how to determine if two strings are anagrams. If two strings are anagrams, then we can re-arrange the letters in the first string to get to the second string. For example, the words `bat`

and `tab`

are anagrams because the letters `b`

, `a`

, and `t`

can be re-arranged to get `t`

, `a`

, `b`

. Another way of looking at it is by comparing the letters and frequencies in both strings. In this example, we see that both `bat`

and `tab`

have `1 b`

, `1 a`

, and `1 t`

. We can use this intuition to solve this Group Anagrams.

To solve group anagrams, we will use a dictionary to store the character frequency as the key and the words that match that character frequeucy as the value to the key. In rough terms, the dictionary will look something like this:

```
{
[1 b, 1 a, 1 t]: ["bat", "tab"]
}
```

Based on the example that Leetcode gave us, our dictionary would look something like this:

```
{
[1 b, 1 a, 1 t]: ["bat"],
[1 n, 1 a, 1 t]: ["nat", "tan"],
[1 a, 1 e, 1 t]: ["ate", "eat", "tea"]
}
```

Once we create this dictionary, we can simply return the values from that dictionary, e.g. something like `return freqs.values()`

The challenge is how to code up the solution. You might initially approach the problem by using the key as a dictionary BUT you cannot do that since dictionary keys CANNOT be dicts or lists. So how are we going to store the character frequencies as the key. For that, we will use tuples. To recap, a tuple is like a list in python but it is immutable, meaning it cannot be modified in any way.

To create a tuple that will represent our character frequencies, we will initialize a list of 26 elements, each set to 0. For this problem, Leetcode assumes that our strings will be lowercase letters from a-z only. So no uppercase or special characters. As a result, we can limit our frequency list to 26 values only. We also want to ensure that the letter number corresponds to the position in the list. So if we have an `a`

in our string, we want it to be counted at the first index, aka the 0th index. And if we have a `z`

it should get counted at the last index.

To do this, we will utilize the `ord()`

function in python, which is built-in. `ord`

will return the Unicode code of a given character. The Unicode value of `a`

is 97, `b`

is 98, and `z`

is 122. But obviously, we don’t have 122 values in our list, we only have 26. So we will shift the unicodes by 97, or the value of `ord('a')`

. So now, when we store our characters, they will get placed in the correct order that we want them to be in.

For example, if our string was `"cab"`

, our character list would look like this: `[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`

. Essentially, we will increment the value at the specificed index if that associated character is in the string. Since `cab`

has `1 a`

, `1 b`

, and `1 c`

, the first three indicies will have values of 1 and every other value will be set to 0 by default. If our input string was `"aaabbb"`

, the first and second indicies would be 3 and everything would be 0. It is important to keep in mind that we will need to store these character lists as tuples, as mentioned previously.

Now that we have created our character frequency tuples, we need a way to store the words that correspond to it. To do so, I will use the `defaultdict`

class in Python which is in the `collections`

module. You import it like: `from collections import defaultdict`

. Since the value of the dictionary will be stored as a list, we can initialize our dictionary as `defaultdict(list)`

. For every string in the input list, we will calculate it’s frequency tuple, and then append it to the word list that corresponds to the frequency tuple like `freqs[f].append(s)`

where `freqs`

is our dictionary, `f`

is the frequency tuple, and `s`

is the string we are looking at.

Our final dictionary will look something like this:

```
{
(1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0): ['eat', 'tea', 'ate'],
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0): ['tan', 'nat'],
(1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0): ['bat']
}
```

From this point, we can return the values in the dictionary, as I previously mentioned.

**Time complexity**: If there are n words in the input list, and each word has, on average k letters, our time complexity is `O(nk)`

**Space complexity**: Given the same assumptions as before, our space complexity will also be `O(nk)`

since that is the total information stored in our dictionary.

The code for this problem can be found here

I hope to keep doing these blogs where I solve a leetcode problem since I believe this will help me get better at explaining my solution in a proper whiteboarding interview.

]]>```
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Output: Because nums[0] + nums[1] == 9, we return [0, 1].
```

On first glance, you might solve this via a brute force approach by checking each possible combination of sums until you reach the target. This approach would yield a time complexity of `O(n^2)`

since you need an outer for loop to traverse all the elements in the array and then an inner for loop to traverse the elements starting from the second one. However this approach is inefficient and you can actually solve it in `O(n)`

time using a dictionary.

The dictionary approach involves storing the value as the key as well as the index at where it’s placed as the value. In the example provided, our dictionary would look something like this:

```
{
2: 0,
7: 1,
11: 2,
15: 3
}
```

if we were to store every single value and index. This represents a worst case possibility if the solution is found at the last index. For this particular problem, we are told that each input array will have exactly one solution.

To simplify matters, if we have a target and a value, we can obviously find the difference. This difference will need to be in the array for us to find a solution. In the example, when we traverse the array, we will start at index 0 which is 2. Since our target is 9, we know that we need to find a 7 in the array for us to return a valid solution. This means we don’t have to keep checking every possible combination since if we can’t find a 7, we know that the solution does not contain 2, or 0, since that is the index where 2 is.

To solve the problem, we will iterate over the array, calculate the difference between the target and value, and check if that difference is in the dictionary. If not, we will append the value and index to the dictionary, since we need to return the index NOT the value.

In the first check, our dictionary is empty. We calculat the difference, which is `9-2=7`

. However 7 is not in our dictionary. So we add the k-v pair, `2: 0`

to it. On the next check, our value is 7. The difference between the target and value is `9-7=2`

. We see that 2 is in the dictionary. So we can return the current index, as well as the index of 2.

If our target was `26`

instead of `9`

, we would solve the problem with the same approach. `26-2=24`

. 24 is not in the dictionary, so we add `2: 0`

. `26-7=19`

. 19 is not in the dictionary, so we add `7: 1`

to it. `26-11=15`

. 15 is not in the dictionary, so we add `11: 2`

. `26-15=11`

. 11 *is* in the dictionary. So we return `[2,3]`

.

**Time Complexity**: If there are n elements in our input array, the worst case time complexity is `O(n)`

if we need to traverse the entire array if the solution is only found at the last index.

**Space Complexity**: Is `O(n)`

since we are storing at most, n elements, in our dictionary.

The code for this can be found here and I hope you enjoyed this write-up.

]]>