Jekyll2023-05-12T21:12:09+00:00https://umanchanda.github.io/feed.xmlUday Manchanda’s BlogUday Manchanda's WebsiteLeetcode 198: House Robber2022-02-11T00:00:00+00:002022-02-11T00:00:00+00:00https://umanchanda.github.io/2022/02/11/house-robber<p>The problem can be found <a href="https://leetcode.com/problems/house-robber/">here</a> and it’s a Medium. The problem is as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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.
</code></pre></div></div>
<p>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 <code class="language-plaintext highlighter-rouge">[5,1,1,5]</code>. 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.</p>
<p>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:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> start
/ \
1 2
/ \ \
3 1 1
</code></pre></div></div>
<p>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:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">max</span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">rob</span><span class="p">[</span><span class="mi">2</span><span class="p">:</span><span class="n">n</span><span class="p">],</span> <span class="nb">max</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="n">n</span><span class="p">])</span>
</code></pre></div></div>
<p>We can start at the beginning of the array and compute the most we could rob at each element.</p>
<ul>
<li>Starting at at house 0, the most we can rob is <code class="language-plaintext highlighter-rouge">1</code> since that is the only house.</li>
<li>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 <code class="language-plaintext highlighter-rouge">2</code> is our answer.</li>
</ul>
<p>If we only consider houses 0, 1, and 2, we can either:</p>
<ul>
<li>Rob houses 0 and 2 -> <code class="language-plaintext highlighter-rouge">1 + 3 = 4</code></li>
<li>Rob house 1 -> <code class="language-plaintext highlighter-rouge">2</code></li>
<li>Compare which one is greater</li>
</ul>
<p>When we include all the homes:</p>
<ul>
<li>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.</li>
<li>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.</li>
<li>We can now do a simple comparison:
<ul>
<li>If we pick the first option, the most we could rob is max(house0, house1) + house3 = max(1,2) + 1 = 3</li>
<li>If we pick the second option, the most we can rob is 4.</li>
<li>3 < 4, so 4 is our answer</li>
</ul>
</li>
</ul>
<p>When we are figuring out how much we can rob at a house, we can look at the previous two results in the array.</p>
<p><code class="language-plaintext highlighter-rouge">| 1 2 | ~~3~~ | 1 |</code></p>
<p>OR</p>
<p><code class="language-plaintext highlighter-rouge">| 1 2 3 | ~~1~~</code></p>
<p>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.</p>
<p>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 <code class="language-plaintext highlighter-rouge">house0</code> and <code class="language-plaintext highlighter-rouge">house1</code> to 0. The for loop would loop through the <code class="language-plaintext highlighter-rouge">nums</code> 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:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">max</span><span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="n">house0</span><span class="p">,</span> <span class="n">house1</span><span class="p">)</span>
</code></pre></div></div>
<p>At this point, our array might look something like this:</p>
<p><code class="language-plaintext highlighter-rouge">[house0, house1, n]</code></p>
<p>As we include more values, the array might start looking like this:</p>
<p><code class="language-plaintext highlighter-rouge">[house0, house1, n, n+1, n+2, ...]</code></p>
<p>We also need to update the values of house0 and house1.</p>
<ul>
<li>The value at house0 is now set to the value at house1</li>
<li>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.</li>
</ul>
<p><strong>Time Complexity</strong>: O(n) because we used a single for loop to traverse the entire nums array</p>
<p><strong>Space Complexity</strong>: O(1) because we are only using variables to store the maximums. A separate array is not required.</p>
<p>The code to the problem can be found <a href="https://github.com/umanchanda/leetcode/blob/main/198-houseRobber.py">here</a> and I hope you enjoyed this writeup.</p>UdayThe problem can be found here and it’s a Medium. The problem is as follows: 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.Leetcode 91: Decode Ways2022-01-30T00:00:00+00:002022-01-30T00:00:00+00:00https://umanchanda.github.io/2022/01/30/decode-ways<p>The problem can be found <a href="https://leetcode.com/problems/decode-ways/">here</a> and it’s a Medium. The problem is as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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).
</code></pre></div></div>
<p>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 <code class="language-plaintext highlighter-rouge">s=12</code>. We analyze the first character, <code class="language-plaintext highlighter-rouge">1</code>. We know that <code class="language-plaintext highlighter-rouge">1</code> corresponds to <code class="language-plaintext highlighter-rouge">A</code> in the alphabet. However, we also know that <code class="language-plaintext highlighter-rouge">1</code> could also be the start of a two digit number from <code class="language-plaintext highlighter-rouge">10-19</code>. Same goes for <code class="language-plaintext highlighter-rouge">2</code> which could correspond to the start of a two digit number from <code class="language-plaintext highlighter-rouge">20-26</code>. If a number is from <code class="language-plaintext highlighter-rouge">3-9</code> 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.</p>
<p>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 <code class="language-plaintext highlighter-rouge">s=12</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> "12"
/ \
"1" "12"
/
"2"
</code></pre></div></div>
<p>We know that the first digit <code class="language-plaintext highlighter-rouge">1</code> coresponds to <code class="language-plaintext highlighter-rouge">"A"</code> and when we next the next digit <code class="language-plaintext highlighter-rouge">2</code> that corresponds to the letter <code class="language-plaintext highlighter-rouge">"B"</code>. 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).</p>
<p>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.</p>
<p>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 <code class="language-plaintext highlighter-rouge">"789"</code>, 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.</p>
<p>Let’s say our input string was <code class="language-plaintext highlighter-rouge">"121"</code>. 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.</p>
<p>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:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dp</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)]</span>
</code></pre></div></div>
<p>could be a way to represent that with code.</p>
<p><strong>Time Complexity</strong>: O(n) because you traverse the input string once.</p>
<p><strong>Space Complexity</strong>: O(n) because you initialize a separate list with the same number of elements as the number of characters in the input string.</p>
<p>The code to the problem can be found <a href="https://github.com/umanchanda/leetcode/blob/main/091-decodeWays.py">here</a> and I hope you enjoyed this writeup.</p>UdayThe problem can be found here and it’s a Medium. The problem is as follows: 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.Leetcode 3: Longest Substring Without Repeating Characters2021-11-25T00:00:00+00:002021-11-25T00:00:00+00:00https://umanchanda.github.io/2021/11/25/longest-substring-without-repeating-characters<p>This is another leetcode problem I solved a while back but wanted to blog about how I solved it. The problem can be found <a href="https://leetcode.com/problems/longest-substring-without-repeating-characters/">here</a> and it’s a Medium. The problem is as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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.
</code></pre></div></div>
<p>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 <code class="language-plaintext highlighter-rouge">O(n^2)</code> since we have the nested for-loop structure. This approach can be dramatically improved to <code class="language-plaintext highlighter-rouge">O(n)</code> by utilizing a common algorithm for solving many array and string questions: the Sliding Window.</p>
<p>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.</p>
<p>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, <code class="language-plaintext highlighter-rouge">a</code>. 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 <code class="language-plaintext highlighter-rouge">b</code>. Since we don’t have a <code class="language-plaintext highlighter-rouge">b</code> in our set, we will add it to our set, and then slide the right pointer again by one. The next character is <code class="language-plaintext highlighter-rouge">c</code>. Since we haven’t seeen a <code class="language-plaintext highlighter-rouge">c</code> in our set just yet, we slide right again.</p>
<p>Now, the next character is an <code class="language-plaintext highlighter-rouge">a</code>. However, we already have an <code class="language-plaintext highlighter-rouge">a</code> in our set. So we need to remove that first <code class="language-plaintext highlighter-rouge">a</code> from our set, which is esesntialy the left pointer. After we remove the <code class="language-plaintext highlighter-rouge">a</code>, we slide BOTH the left and right pointers. Our window (set) now contains <code class="language-plaintext highlighter-rouge">b</code>, <code class="language-plaintext highlighter-rouge">c</code>, and <code class="language-plaintext highlighter-rouge">a</code>. The next character is <code class="language-plaintext highlighter-rouge">b</code>, which already exists in our set. So we do the same thing for the previous character.</p>
<p>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.</p>
<p>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 <code class="language-plaintext highlighter-rouge">r - l</code>. Once our right pointer hits the end of the string, we can stop iterating through the string.</p>
<p><strong>Time Complexity</strong>: We are guaranteed to do a single traversal of the string. So our time complexity is <code class="language-plaintext highlighter-rouge">O(n)</code>.</p>
<p><strong>Space Complexity</strong>: 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 <code class="language-plaintext highlighter-rouge">O(n)</code>.</p>
<p>The code to the problem can be found <a href="https://github.com/umanchanda/leetcode/blob/main/003-longestSubstringWithoutRepeatingCharacters.py">here</a> and I hope you enjoyed this writeup.</p>UdayThis is another leetcode problem I solved a while back but wanted to blog about how I solved it. The problem can be found here and it’s a Medium. The problem is as follows: 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.Leetcode 49: Group Anagrams2021-11-24T00:00:00+00:002021-11-24T00:00:00+00:00https://umanchanda.github.io/2021/11/24/group-anagrams<p>Today I wil be discussing one of the leetcode problems I solved a few days ago. This one is Leetcode 49: Group Anagrams and it’s a Medium. You can find it <a href="https://leetcode.com/problems/group-anagrams/">here</a>. The problem is as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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"]]
</code></pre></div></div>
<p>This is a little tricky at first but after some thinking, you can solve it using a dictionary/map.</p>
<p>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 <code class="language-plaintext highlighter-rouge">bat</code> and <code class="language-plaintext highlighter-rouge">tab</code> are anagrams because the letters <code class="language-plaintext highlighter-rouge">b</code>, <code class="language-plaintext highlighter-rouge">a</code>, and <code class="language-plaintext highlighter-rouge">t</code> can be re-arranged to get <code class="language-plaintext highlighter-rouge">t</code>, <code class="language-plaintext highlighter-rouge">a</code>, <code class="language-plaintext highlighter-rouge">b</code>. Another way of looking at it is by comparing the letters and frequencies in both strings. In this example, we see that both <code class="language-plaintext highlighter-rouge">bat</code> and <code class="language-plaintext highlighter-rouge">tab</code> have <code class="language-plaintext highlighter-rouge">1 b</code>, <code class="language-plaintext highlighter-rouge">1 a</code>, and <code class="language-plaintext highlighter-rouge">1 t</code>. We can use this intuition to solve this Group Anagrams.</p>
<p>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:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
[1 b, 1 a, 1 t]: ["bat", "tab"]
}
</code></pre></div></div>
<p>Based on the example that Leetcode gave us, our dictionary would look something like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
[1 b, 1 a, 1 t]: ["bat"],
[1 n, 1 a, 1 t]: ["nat", "tan"],
[1 a, 1 e, 1 t]: ["ate", "eat", "tea"]
}
</code></pre></div></div>
<p>Once we create this dictionary, we can simply return the values from that dictionary, e.g. something like <code class="language-plaintext highlighter-rouge">return freqs.values()</code></p>
<p>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.</p>
<p>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 <code class="language-plaintext highlighter-rouge">a</code> in our string, we want it to be counted at the first index, aka the 0th index. And if we have a <code class="language-plaintext highlighter-rouge">z</code> it should get counted at the last index.</p>
<p>To do this, we will utilize the <code class="language-plaintext highlighter-rouge">ord()</code> function in python, which is built-in. <code class="language-plaintext highlighter-rouge">ord</code> will return the Unicode code of a given character. The Unicode value of <code class="language-plaintext highlighter-rouge">a</code> is 97, <code class="language-plaintext highlighter-rouge">b</code> is 98, and <code class="language-plaintext highlighter-rouge">z</code> 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 <code class="language-plaintext highlighter-rouge">ord('a')</code>. So now, when we store our characters, they will get placed in the correct order that we want them to be in.</p>
<p>For example, if our string was <code class="language-plaintext highlighter-rouge">"cab"</code>, our character list would look like this: <code class="language-plaintext highlighter-rouge">[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]</code>. Essentially, we will increment the value at the specificed index if that associated character is in the string. Since <code class="language-plaintext highlighter-rouge">cab</code> has <code class="language-plaintext highlighter-rouge">1 a</code>, <code class="language-plaintext highlighter-rouge">1 b</code>, and <code class="language-plaintext highlighter-rouge">1 c</code>, 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 <code class="language-plaintext highlighter-rouge">"aaabbb"</code>, 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.</p>
<p>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 <code class="language-plaintext highlighter-rouge">defaultdict</code> class in Python which is in the <code class="language-plaintext highlighter-rouge">collections</code> module. You import it like: <code class="language-plaintext highlighter-rouge">from collections import defaultdict</code>. Since the value of the dictionary will be stored as a list, we can initialize our dictionary as <code class="language-plaintext highlighter-rouge">defaultdict(list)</code>. 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 <code class="language-plaintext highlighter-rouge">freqs[f].append(s)</code> where <code class="language-plaintext highlighter-rouge">freqs</code> is our dictionary, <code class="language-plaintext highlighter-rouge">f</code> is the frequency tuple, and <code class="language-plaintext highlighter-rouge">s</code> is the string we are looking at.</p>
<p>Our final dictionary will look something like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
(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']
}
</code></pre></div></div>
<p>From this point, we can return the values in the dictionary, as I previously mentioned.</p>
<p><strong>Time complexity</strong>: If there are n words in the input list, and each word has, on average k letters, our time complexity is <code class="language-plaintext highlighter-rouge">O(nk)</code></p>
<p><strong>Space complexity</strong>: Given the same assumptions as before, our space complexity will also be <code class="language-plaintext highlighter-rouge">O(nk)</code> since that is the total information stored in our dictionary.</p>
<p>The code for this problem can be found <a href="https://github.com/umanchanda/leetcode/blob/main/049-groupAnagrams.py">here</a></p>
<p>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.</p>UdayToday I wil be discussing one of the leetcode problems I solved a few days ago. This one is Leetcode 49: Group Anagrams and it’s a Medium. You can find it here. The problem is as follows: [1 b, 1 a, 1 t]: [“bat”, “tab”] [1 b, 1 a, 1 t]: [“bat”], [1 n, 1 a, 1 t]: [“nat”, “tan”], [1 a, 1 e, 1 t]: [“ate”, “eat”, “tea”]Leetcode 1: Two Sum2021-11-24T00:00:00+00:002021-11-24T00:00:00+00:00https://umanchanda.github.io/2021/11/24/two-sum<p>This is another leetcode problem that I had actually solved a long time but wanted to blog about it. This one is the famous (or infamous) Two Sum, the very first Leetcode problem in the problems list. The link to the problem is <a href="https://leetcode.com/problems/two-sum/">here</a>. The problem is as follows:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>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].
</code></pre></div></div>
<p>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 <code class="language-plaintext highlighter-rouge">O(n^2)</code> 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 <code class="language-plaintext highlighter-rouge">O(n)</code> time using a dictionary.</p>
<p>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:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
2: 0,
7: 1,
11: 2,
15: 3
}
</code></pre></div></div>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<p>In the first check, our dictionary is empty. We calculat the difference, which is <code class="language-plaintext highlighter-rouge">9-2=7</code>. However 7 is not in our dictionary. So we add the k-v pair, <code class="language-plaintext highlighter-rouge">2: 0</code> to it. On the next check, our value is 7. The difference between the target and value is <code class="language-plaintext highlighter-rouge">9-7=2</code>. We see that 2 is in the dictionary. So we can return the current index, as well as the index of 2.</p>
<p>If our target was <code class="language-plaintext highlighter-rouge">26</code> instead of <code class="language-plaintext highlighter-rouge">9</code>, we would solve the problem with the same approach. <code class="language-plaintext highlighter-rouge">26-2=24</code>. 24 is not in the dictionary, so we add <code class="language-plaintext highlighter-rouge">2: 0</code>. <code class="language-plaintext highlighter-rouge">26-7=19</code>. 19 is not in the dictionary, so we add <code class="language-plaintext highlighter-rouge">7: 1</code> to it. <code class="language-plaintext highlighter-rouge">26-11=15</code>. 15 is not in the dictionary, so we add <code class="language-plaintext highlighter-rouge">11: 2</code>. <code class="language-plaintext highlighter-rouge">26-15=11</code>. 11 <em>is</em> in the dictionary. So we return <code class="language-plaintext highlighter-rouge">[2,3]</code>.</p>
<p><strong>Time Complexity</strong>: If there are n elements in our input array, the worst case time complexity is <code class="language-plaintext highlighter-rouge">O(n)</code> if we need to traverse the entire array if the solution is only found at the last index.</p>
<p><strong>Space Complexity</strong>: Is <code class="language-plaintext highlighter-rouge">O(n)</code> since we are storing at most, n elements, in our dictionary.</p>
<p>The code for this can be found <a href="https://github.com/umanchanda/leetcode/blob/main/001-twoSum.py">here</a> and I hope you enjoyed this write-up.</p>UdayThis is another leetcode problem that I had actually solved a long time but wanted to blog about it. This one is the famous (or infamous) Two Sum, the very first Leetcode problem in the problems list. The link to the problem is here. The problem is as follows:End of My Undergraduate Career2019-05-16T00:00:00+00:002019-05-16T00:00:00+00:00https://umanchanda.github.io/2019/05/16/end-of-my-undergraduate-career<p>So today was the last final I had of my undergraduate career (well I hope so!). This semester was in many ways a microcosm of my college career as whole, full of its ups and downs but finally ending. It’s been a long ride and I’ve learned quite a bit in the five years it took me to get my degree. As long as I pass my classes this semester, I’ll officially have my BS in Computer Science and on my way to Richmond to start my career as a software engineer at Capital One in August.</p>UdaySo today was the last final I had of my undergraduate career (well I hope so!). This semester was in many ways a microcosm of my college career as whole, full of its ups and downs but finally ending. It’s been a long ride and I’ve learned quite a bit in the five years it took me to get my degree. As long as I pass my classes this semester, I’ll officially have my BS in Computer Science and on my way to Richmond to start my career as a software engineer at Capital One in August.My First Blog Post2019-05-07T00:00:00+00:002019-05-07T00:00:00+00:00https://umanchanda.github.io/2019/05/07/my-first-blog<p>Hello and welcome to my blogs. I will be updating this periodically with new posts regarding my personal projects and things I would like to learn. Once I begin my job at Capital One, I plan on blogging about my experiences there.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">hello_world</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="k">return</span><span class="p">(</span><span class="s">"Hello, %s!"</span> <span class="o">%</span> <span class="n">name</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">hello_world</span><span class="p">(</span><span class="s">'Uday'</span><span class="p">))</span>
<span class="c1">#=> prints 'Hello, Uday!' to STDOUT.</span></code></pre></figure>UdayHello and welcome to my blogs. I will be updating this periodically with new posts regarding my personal projects and things I would like to learn. Once I begin my job at Capital One, I plan on blogging about my experiences there.Reflecting Back on College2019-05-07T00:00:00+00:002019-05-07T00:00:00+00:00https://umanchanda.github.io/2019/05/07/reflecting-back-on-college<p>As I mentioned, I’ll be graduating in exactly two weeks at NJIT. It’s been a long road and I encountered a few roadblocks along the way (who doesn’t?) but in the end, I’m glad I finally have that degree and diploma. Finally, I can say that I have a college degree and not simply working towards one. I’m having conflicting thoughts. Part of me is happy to be finally be done with college. It’s been a long and hard road and as anyone can attest to, CS is a difficult major with long hours and stressful, sleepless nights. Another part of me is nostalgic for what I’ve accomplished as well as the friends I’ve made along the way.</p>UdayAs I mentioned, I’ll be graduating in exactly two weeks at NJIT. It’s been a long road and I encountered a few roadblocks along the way (who doesn’t?) but in the end, I’m glad I finally have that degree and diploma. Finally, I can say that I have a college degree and not simply working towards one. I’m having conflicting thoughts. Part of me is happy to be finally be done with college. It’s been a long and hard road and as anyone can attest to, CS is a difficult major with long hours and stressful, sleepless nights. Another part of me is nostalgic for what I’ve accomplished as well as the friends I’ve made along the way.