Skip to content

Blog

Leetcode 1352: Product of the Last K Numbers

Cool so looks like we get another System Design problem today. As usual, Leetcode just casually gives us the defualt JS prototyping functions together like a madlad template. This time we accepting numbers in a sort of data stream in one method. The other method being for taking the previous K values recieved, and returning the product of all of them multiplied together.

At first I didnt even care about the follow up, I just wanted to do it fast and pass it so I didnt have to worry about ruining my daily streak. So I just did an array push for my add() method, and then for my getProduct() method I just took a slice of my array at the ending depending on the k size given and then reduced using multiplacation to return the answer. This worked out good, but was pretty gross with a 1000ms being used. Definately not the O(1) goal that follow up sets us up for.

After that, and after some messing around with the testcase that a zero happens, I ended up instead keeping an array of multiplied prefix sums of my values, and a current prefix sum varible to just quickly take the current prefix sum value dividied by the past prefix sum value based on K offset to quickly get the answer.

Leetcode 2516: Take K of Each Character From Left and Right

About

This leetcode problem asks use to find the minimal number of operations needed to get AT LEAST k amounts of a, b and c characters. For each operation, you are able to either remove a letter from the beginning or end of the given string.

Example

“aabaaaacaabc” k=2

The minimal number of operations needed would be 8. From the left of the given string we can remove letters “aab”. From the right of the given string we can remove letters “caabc”. With these 8 removal operations, we can get 4 a’s, 2 b’s and 2 c’s, which meet our “AT LEAST” k of each letter requirement.

Thoughts

At first, I was thinking it was some kind of greedy deque problem. At first glances, It felt like the problem was asking to choose optimally between either the left side vs the right side of the char array.

However, I then realized that it sounded more like finding an optimal prefix and suffix of the string such that you had all the letter you needed. Seeing I was finding a string prefix and suffix, I knew that I would need some kind of Two Pointer approach for this problem.

After getting a little frustrated, I peaked at the topic tags and saw “Sliding Window”. Then it clicked, a lot of Leetcode sliding window problems are phrased like, for this continuous sub array in your array of data, find X criteria or frequencies. This problem sounded similar, but the main difference was we are concerned about what is on the outside of the sliding window, versus what’s on the inside of the sliding window.

Implementation

In Javascript, I first find the frequencies of a,b and c present in my given string. If the amount of letters in the whole string are less than K for any of the letters, I then just return a -1. If the amount of letters in the whole string are greater than K, a while loop is used to start building my sliding window.

During each iteration, sliding window’s R pointer slides to the right, and for each letter it comes across it subtracts from my frequency map of letters. If at any point a letter’s frequency becomes less than K, I start moving the left pointer to the right. For each letter my left pointer hits, I increase the frequency of that letter in the frequency map.

This ensures that my sliding window never takes more letters than it can from the string prefix or suffix. In other words, this makes sure that my sliding window is the largest window of characters that can take up the space between the smallest need prefix and suffix of the string.

Lastly, for each iteration we keep track of the maxRange of our sliding window. We then return the given string length - maximum range of the sliding window. We return this because the minimal of letter removal operations is equal the amount of character not present inside our sliding window. The answer therefor is basically the smallest possible string prefix and string suffix.

TLDR

  1. Find the minimal number of letters from beginning or end of string to remove for “at least” K letters.

  2. At first thought it was a greedy problem, but it’s actually a slightly unusual sliding window / two pointers problem.

  3. Use Sliding window to find the largest range between the smallest needed prefix and suffix of string.

  4. The sliding window is valid if your remaining letter frequencies do not go below K elements.

Closing Thoughts

This is a very interesting sliding window problem. Instead of following the usual pattern of focusing on the internal state of the Sliding window element frequencies, it focuses on how your sliding window impacts the external state of you total frequencies of each letter in the given string.

Leetcode 2275: Largest Combination With Bitwise AND Greater Than Zero

About

This problem focuses on finding combinations of numbers from the given array such that the bitwise & AND of all numbers are greater than or equal to 1. Out of all combinations of elements, we return the size of the largest possible combination length.

For example, [1,2,3,4,5] = 3, since the greatest combination length possible would be 1,3,5. This is because 1&3&5 is equal to 1.

Thoughts

An important thing to note about using the bitwise AND & operator is that between two numbers, only the ON (1) bits locations can stay one when performing the AND & bitwise operation. For example, 1 AND 2 would equal zero since they do not share any ON (1) bit locations, but 1 AND 3 would equal 1 since both 1 and 3 have the 1 bit turned on.

  1. 1 = 01, 2 = 10, 01 & 10 = 00
  2. 1 = 01, 3 = 11, 01 & 11 = 01

With this property noted, we can say that for a combination of numbers bitwise AND together have to share ON (1) bit locations among all of them to be greater than zero. In other words, as soon as we reach a number with a bit location that is off, said bit location in the ending result is also turned off.

Seeing this, I decided an optimal way to organize these array elements into valid combinations would be using a hashmap data structure. A hashmap can assign elements into groups based on what bit locations they have flipped on. All elements in a group are in common, as they would all share a specific ON (1) bit location.

Implementation

To solve this problem, I used the built-in Javascript Map() object to record the frequencies of elements in the array that share a specific bit location. To update both myMap and the answer variable, I created a function named “nya” on each candidate in the candidates’ array. The function nya can check each ON(1) bit location a candidate has and update the frequency of that bitmask location if it is on. Lastly, nya can update my ans variable with the maximal length of a valid combination.

For example, for test case [1,2,3,4,5], these are all my valid combinations. To save on memory space, I can update the frequency at a given bit location key instead of maintaining an array of elements at that key. In other words, sorting into buckets, but instead, I keep track of the buckets’ lengths.

  1. [1,3,5] = 3
  2. [2,3] = 2
  3. [4,5] = 2

ans = 3

Closing Thoughts

This is a pretty fun bitwise & hashmap combo problem. While coding this solution, I almost did not go with a frequency map, but instead went with keeping track of all elements in an array inside of the hashmap. Switching to keeping track of the frequency of all elements that shared an ON bit location instead of all the elements in that combo saved my bacon for sure time complexity and memory space-wise.

Leetcode 3011: Find if Array Can Be Sorted

About

There are two main parts to this problem. First, we need to be able to preform a sort on the array of values. Second, we must evaluate whether two elements in the array need to be swapped, and whether they are swappable given their count of on (1) in their binary representation of themselves. If the given array is already sorted, we can return true. If the given array is unsorted, then we must return whether it can become sorted by swapping elements when their bit counts are equal to each other. Returning false means that we have reached a point where the array is unsorted, and elements are different bit counts from each other, meaning it’s impossible to complete the swap operation.

For example:

  1. [1,5,2] = false, 5 and 2 can’t be swapped, even though they need to be swapped
  2. [1,2,3,4,5] = true, sure some numbers can’t be swapped, but since its already sorted we don’t need to worry

Thoughts

Since this is a bitwise problem, a while loop can find the number of on (1) bits a number has. Also, an ideal sorting algorithm to use would be bubble sort, since the problem specifies you are preforming swaps between elements. Since the main idea is to test for bit counts and whether elements in the array are less than each other, bubble sort is the first thing that popped into my head. With bubble sort, I could check how elements values differ from each other, as well as how their bit counts differ from each other.

Implementation

For my solution I went with a bubble sort approach, since bubble sort is well known for being a sort algorithm that preforms a bunch of swaps between a left and right pointer. By using a bubble sort to implement a solution, I could also include a check during swaps to check if the two elements I’m swapping at the time are different bit counts. If at any point they are different bit counts and need to be swapped, I can simply exit early and return false. Otherwise, I continue on with my business until the array is fully sorted and return true.

For finding the bit count of on (1) bits of a number, I simply use a while loop that counts the & of each first bit. Then to iterate down, I just do an arithmetic shift right, >> 1, to effectively half and floor the number each iteration until the number I am checking reaches zero.

Closing Thoughts

After rereading the question, I noticed that leetcode did specify that only two ADJACENT elements can be swapped in one operation. While my solution passes all test cases, my solution does technically break the only ADJACENT elements rule. https://www.geeksforgeeks.org/bubble-sort-algorithms-by-using-javascript/ The bubble sort algorithm template on geeksforgeeks actually follows this rule a bit better, but at the end of the day still gets the job done :p

Leetcode 1106: Parsing A Boolean Expression

About

The goal of this problem is to take a string representation of booleans and functions, then return the expected boolean value after completing the function. For example, we could have a “t” symbol for a true boolean, a “f” symbol for a false boolean, a ! for a not function, and a & and | for functions that take all elements inside of a () and return the boolean of bitwise anding and bitwise or ing all elements respectively.

For example:

  1. &(|(f)) = Return the bitwise or of one false, then return the bitwise & of one false
  2. |(f,f,f,t) = Return the bitwise or of three falses and one true
  3. !(&(f,t)) = Find the bitwise and of both false and true, then return the flipped / inverted result.

Thoughts

After reading the problem, I stopped panicking about its high difficulty rating and thought back to reading up on JSFuck and BrainFuck, so decided to just make an eval statement do the work for me. I knew this would be like implementing a very minimal programming language interpreter, since “t” and “f” are like boolean constants, and the !&| symbols are like functions that accept input and return an output value.

Implementation

First I use a series of replaceAll commands to slightly edit the given expression. A big reason for replacing these symbols is due to the fact that JS functions can not be just one special character like !&|, since those characters are reserved for bitwise operations. Once I have my expression edited, I then append some string representations of JS functions for returning the flipped value of a given boolean, as well as returning the bitwise OR / AND of all elements given in the function’s args. Lastly, I then return the result given by running the JS eval command with my slightly modified string.