Saturday, October 31, 2020

Minimum number of perfect squares whose sum equals to given number

Problem: Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

Example:

Input: n = 34
Output: 2
Explanation: 34 = 25 + 9.


Approach: We can solve it using recursive approach. The recursion will be something like:

  • result = n
  • WHILE a * a <= n
    • result = Min (result, 1 + Fn(n - a*a))
That means we will recursively calculate for every n - x where x is every perfect square less than or equals to n and then take its minimum. It will solve our problem but the complexity will be exponential. If we look at it again we are kind of calculating same sub problems repeatedly. This tells us we can use DP here. 
We can have a Table where Table[i] tells minimum number of perfect squares whose sum equals to i. Obviously Table[n] is our answer. Here is how we can fill the table:
  • Table[0...3] = {0...3}
  • Table[i] = i
  • Foreach j where j = 1 to j * j <= i
    • Table[i] = Min(Table[i], 1 + Table[i - j *j])

That's all!


Implementation in C#:

        public static int MinNumPerfectSquares(int n)

        {

            if (n <= 3)

            {

                return n;

            }

            if (IsPerfectSquare(n))

            {

                return 1;

            }

            int[] table = new int [n + 1];

            for (int i = 0; i <= 3; ++i)

            {

                table[i] = i;

            }

            for (int i = 4; i <= n; ++i)

            {

                table[i] = i;

                for (int j = 1; j * j <= i; ++j)

                {

                    table[i] = Math.Min(table[i], 1 + table[i - j * j]);

                }

            }

            return table[n];

        }


Complexity: O(nlogn)

Find the Celebrity

Problem: Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them.

Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: "Hi, A. Do you know B?" to get information of whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense).

You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n), your function should minimize the number of calls to knows.

Note: There will be exactly one celebrity if he/she is in the party. Return the celebrity's label if there is a celebrity in the party. If there is no celebrity, return -1.


Approach: Use two pointers. One from the start say A and one from the end B. Initial values of A and B are 0 and n - 1 respectively. Now have a loop:

  • WHILE A < B
    • IF Knows(A, B) 
      • A = A + 1 // A knows B so A can't be a celebrity
    • ELSE
      • B = B - 1 // A doesn't know B so B can't be celebrity
At the end we will get a potential candidate (=  A or B as A and B will be same at the end of loop). Now we will run another loop from i = 0 to n - 1 and check if each and every ith person, where i is not equals to candidate, knows candidate and candidate does not know i. If for every i this condition is satisfied then the candidate is celebrity otherwise we can safely tell that there are no celebrity in the party:

  • For i = 0 to n - 1
    • IF i != candidate AND (Knows(candidate, i) OR !Knows(i, candidate))
      • return -1
  • return candidate

Implementation in C#:

        public static int FindCelebrity(int n)

        {
            if (n == 0)
            {
                return -1;
            }

            int a = 0, b = n - 1;

            while(a < b)
            {
                if (Knows(a, b))
                {
                    ++a;
                }
                else
                {
                    --b;
                }
            }
            
            // Get the potential candidate, now check if it is really a celebrity or not 
            return IsCandidateIsCelebrity(n, a) ? a : -1;
        }

        private static bool IsCandidateIsCelebrity(int n, int candidate)
        {
            for (int i = 0; i < n; ++i)
            {
                if (i != candidate && (!Knows(i, candidate) || Knows(candidate, i)))
                {
                    return false;
                }
            }

            return true;
        }


Complexity: O(n)

H-Index

Problem: Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index. The h-index is defined as the maximum value of h such that the given author/journal has published h papers that have each been cited at least h times.

Example:

Input: citations = [10,9,8,7,3]
Output: 4 
Explanation: [10,9,8,7,4] means the researcher has 5 papers in total and each of them had 
received 10, 9, 8, 7, 4 citations respectively.   Since the researcher has 4 papers with at least 4 citations each and the                 remaining one has only 3 citations i.e. less than 4, his h-index is 4.


Approach: This is a simple problem to solve. Just use sorting.


Implementation in C#:

        public static int HIndex(int[] citations)

        {

            if (citations?.Length == 0)

            {

                return 0;

            }

            Array.Sort(citations);

            Array.Reverse(citations);

            int hIndex = 0;

            for (int i = 0; i < citations.Length; ++i)

            {

                if (i + 1 > citations[i])

                {

                    break;

                }

                hIndex = Math.Max(hIndex, Math.Min(i + 1, citations[i]));

            }

            return hIndex;

        }


Complexity: O(nlogn)

Friday, October 30, 2020

Find the n-th ugly number.

Problem: Write a method to find the nth ugly number.

Example(Taken from leetcode):

Input: n = 10
Output: 12
Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.


Approach: Use DP. Maintain a Table where Table[i] tells the (i + 1)th ugly number. Obviously Table[n - 1] will be our answer. Here is how we fill this table:

  • Table[0] = 1 
  • Maintain three variables; NumOfTwo, NumOfThree and NumOfFive. These variable will tell how many number of 2s, 3s or 5s are involved in the product till now. Initialized to 0.
  • FOR i = 0 to n - 1 // first ugly number is already in the table
    • NextUglyNumber = Min ( 2 * Table[NumOfTwo], 3 * Table[NumOfThree ], 5 * Table[NumOfFive])
    • Add NextUglyNumber to Table
    • Increment one of NumOfTwo, NumOfThree and NumOfFive based on which one of them out of 2 * Table[NumOfTwo], 3 * Table[NumOfThree ] and 5 * Table[NumOfFive] is minimum.
  • Return Table[n - 1]


Implementation in C#: 

        public static int NthUglyNumber(int n)

        {

            if (n == 0)

            {

                return 0;

            }

            List<int> table = new List<int> { 1 };

            int numOfTwo = 0, numOfThree = 0, numOfFive = 0;

            for (int i = 0; i < n - 1; ++i)

            {

                int nextUglyNumber = Min(2 * table[numOfTwo], 3 * table[numOfThree], 5 * table[numOfFive]);

                if (nextUglyNumber == 2 * table[numOfTwo])

                {

                    ++numOfTwo;

                }

                if (nextUglyNumber == 3 * table[numOfThree])

                {

                    ++numOfThree;

                }

                if (nextUglyNumber == 5 * table[numOfFive])

                {

                    ++numOfFive;

                }

                table.Add(nextUglyNumber);

            }

            return table.Last();

        }


        private static int Min(params int[] values)

        {

            return Enumerable.Min(values);

        }


Complexity: O(n)

Ugly Number

Problem: Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. Write a method to check whether a given number is an ugly number.

Example:

Input: 10
Output: true
Explanation: 10 = 2 × 5


Approach: Nothing to explain. Just look at the code.


Implementation in C#:

        public bool IsUgly(int num)

        {

            if (num == 0)

            {

                return false;

            }


            while (num != 1)

            {

                if (num % 2 == 0)

                {

                    num /= 2;

                }

                else if (num % 3 == 0)

                {

                    num /= 3;

                }

                else if (num % 5 == 0)

                {

                    num /= 5;

                }

                else

                {

                    return false;

                }

            }

            return true;

        }


Complexity: O(logn)

Find two elements that appear only once in array

Problem: Given an integer array nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

Example:

Input: nums = [1,2,1,3,2,4]
Output: [3,4]


Approach: It is a simple problem. Can be easily understood by looking at the code.


Implementation in C#:

        public int[] FindTwoNumbers(int[] nums)

        {

            if (nums?.Length <= 1)

            {

                return null;

            }

            if (nums.Length == 2)

            {

                return nums;

            }

            int[] result = new int[2];

            int xor = 0;

            // Say our target number are a and b. Xoring all the elements of array will produce a xor b

            foreach(int num in nums)

            {

                xor ^= num;

            }

            // Right now xor will have a xor b

            // Get the rightmost set bit, means the right most bit where a and b have different bits

            int setBit = xor & ~(xor - 1);

            // Now just take XOR separately based on above bit to get a and b 

            foreach (int num in nums)

            {

                if ((num & setBit) != 0)

                {

                    result[0] ^= num;

                }

                else

                {

                    result[1] ^= num;

                }

            }

            return result;

        }


Complexity: O(n)

Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.

Example:

Input: 29
Output: 2 
Explanation: 2 + 9 = 11, 1 + 1 = 2. 
             Since 2 has only one digit, return it.

Approach: Algorithm is simple:

  • IF num eq 0, return 0
  • ELSE IF num % 9 eq 0, return 9
  • ELSE return num % 9
Why num % 9 works. Let's see:

Let’s say that your positive number is N. Writing N in terms of its digits is

N = (sum) [ d[j] * 10^j ], where d[0], d[1], d[2], …. are the digits of N. The sum starts at j=0.

Notice now that 10^1 = (9*1 + 1), 10^2 = (9*11 + 1), 10^3 = (9*111 + 1), and so on. Rearrange to write

N = (9*1 + 1) d[0] + (9*11 + 1) d[1] + (9*111 + 1) d[2] + …

= 9 * (1 d[0] + 11 d[1] + 111 d[2] + ….. ) + d[0] + d[1] + d[2] + ….

= multiple of 9 + d[0] + d[1] + d[2] + ….

Thus N (mod 9) = d[0] + d[1] + d[2] + ….


Implementation in C#: 

        public int AddDigits(int num) 
       {
            if (num == 0)
            {
                return 0;
            }
        
            int sum = num % 9;
            return sum == 0 ? 9 : sum;
        }


Complexity: O(1)

Given a binary tree, return all root-to-leaf paths.

Example:

Input:

   1
 /   \
2     3
 \
  4

Output: ["1->2->4", "1->3"]

Explanation: All root-to-leaf paths are: 1->2->4, 1->3


Approach: Using Pre-Order traversal. Approach is easy to understand even by just looking at the code.


Implementation in C#:

        public IList<string> RootToLeafPaths()

        {

            List<string> result = new List<string>();

            if (this.Root == null)

            {

                return result;

            }

            string currPath = string.Empty;

            this.RootToLeafPaths(this.Root, currPath, ref result);

            return result;

        }


        private void RootToLeafPaths(BinaryTreeNode node, string currPath, ref List<string> result)

        {

            if (string.IsNullOrWhiteSpace(currPath))

            {

                currPath = $"{node.Value}";

            }

            else

            {

                currPath += $"->{node.Value}";

            }

            // Get the leaf node, Add current path to result

            if (node.LeftNode == null && node.RightNode == null)

            {

                result.Add(currPath);

                return;

            }

            if (node.LeftNode != null)

            {

                this.RootToLeafPaths(node.LeftNode, currPath, ref result);

            }

            if (node.RightNode != null)

            {

                this.RootToLeafPaths(node.RightNode, currPath, ref result);

            }

        }


Complexity: O(n)

Different Ways to Add Parentheses

Problem: Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +, - and *.

Example(Taken from leetcode):

Input: "2-1-1"
Output: [0, 2]
Explanation: 
((2-1)-1) = 0 
(2-(1-1)) = 2


Approach: We can solve this problem by parenthesizing all possible valid substring of the expression and then evaluating them, but as you can see it involves solving lots of subproblems which are already solved before or you can say solving lots of repeating subproblem which clearly tells us that we can use DP here. 

We can have a HashMap whose key is substring and value is all possible results for that substring. Basically we will memorize the results of a substring and whenever we try to solve the same substring again, we just get the result from the HashMap. 

For each character in the input string, we check if the current character is operator then we divide the input into two parts; one before operator and second after operator. Recursively solve each part and then combine the result in all possible ways.


Implementation in C#:

        public static IList<int> DiffWaysToCompute(string input)

        {

            if (string.IsNullOrWhiteSpace(input))

            {

                return new List<int>();

            }

            Dictionary<string, List<int>> memory = new Dictionary<string, List<int>>();

            return DiffWaysToCompute(input, ref memory);

        }


        private static List<int> DiffWaysToCompute(string input, ref Dictionary<string, List<int>> memory)

        {

            // Checking if the current string is already solved

            if (memory.ContainsKey(input))

            {

                return memory[input];

            }

            List<int> result = new List<int>();

            for (int i = 0; i < input.Length; ++i)

            {

                if (IsOperator(input[i]))

                {

                    List<int> resultsBeforeOperator = DiffWaysToCompute(input.Substring(0, i), ref memory);

                    List<int> resultAfterOperator = DiffWaysToCompute(input.Substring(i + 1), ref memory);

                    foreach(int preNum in resultsBeforeOperator)

                    {

                        foreach(int postNum in resultAfterOperator)

                        {

                            switch(input[i])

                            {

                                case '+': result.Add(preNum + postNum);

                                    break;

                                case '-': result.Add(preNum - postNum);

                                    break;

                                case '*': result.Add(preNum * postNum);

                                    break;

                            }

                        }

                    }                  

                }

            }

            // The whole string was a number

            if (result.Count == 0)

            {

                result.Add(int.Parse(input));

            }

            memory.Add(input, result);

            return result;

        }


        private static bool IsOperator(char ch)

        {

            return ch == '+' || ch == '-' || ch == '*';

        }


Complexity: O(2^n)

Thursday, October 29, 2020

[Avalara Question] Perfect Substring

Problem: Given a string s (contains only digits) and an integer k, a perfect substring is where each and every character appeared exactly k times. Write a method which returns the number of perfect substrings of string s.

Example:

Input: s = "1020122", k = 2
Output: 2
Explanation: 
"102012" and "22" 


Approach: The idea is simple. Traverse through all substrings. For each substring we can check if frequency of all the characters are exactly k then we increment the count. To count frequency, we can maintain a hash.

 

Implementation in C#:

        public static int PerfectSubstring(string s, int k)

        {

            int result = 0;

            if ( s?.Length < k)

            {

                return result;

            } 

            for (int i = 0; i < s.Length; ++i)

            {

                // It is given that the input string only contains digit so we can take array of 10 integers for hashing

                int[] frequency = new int[10];

                for (int j = i; j < s.Length; ++j)

                {

                    int index = s[j] - '0';

                    ++frequency[index];

                    // frequency of a character more than k, no need to process further

                    if (frequency[index] > k)

                    {

                        break;

                    }

                    else if (frequency[index] == k && ValidateFrequency(frequency, k))

                    {

                        ++result;

                    }

                }

            }

            return result;

        }


        private static bool ValidateFrequency(int[] frequency, int k)

        {

            for (int i = 0; i < frequency.Length; ++i)

            {

                if (frequency[i] != 0 && frequency[i] != k)

                {

                    return false;

                }

            }

            return true;

        }


Complexity: O(n^2)

Find the Jar with contaminated pills

Problem: You have 5 jars of pills. Each pill weighs 10 grams, except for contaminated pills contained in one jar, where each pill weighs 9 grams. Given a scale, how could you tell which jar had the contaminated pills in just one measurement?

Solution: Take following number of pills from each jar:

  • Jar 1: 1 pill
  • Jar 2: 2 pills
  • Jar 3: 3 pills
  • Jar 4: 4 pills
  • Jar 5: 5 pills
Take the weight of all these 15 pills. Ideally if all the pills are of same weight i.e. 10 grams then the total weight should have been (10 X 15 =) 150 grams but we know that in one of the jar the pill weight is 9 grams i.e. 1 gram lesser than the usual pills. Let's see how it can impact this calculations:
  1. If Jar 1 has contaminated pills  then the total weight would be 1 X 1 = 1 gram lesser than 150 grams. That means if total weight is (150 - 1 =) 149 grams then we can say Jar 1 has contaminated pills.
  2. If Jar 2 has contaminated pills then the total weight would be 2 X 1 = 2 gram lesser than 150 grams. That means if total weight is (150 - 2 =) 148 grams then we can say Jar 2 has contaminated pills.
  3. With the same logic we can say:
    1. total weight is (150 - 3 =) 147 then answer is Jar 3
    2. total weight is (150 - 4 =) 146 then answer is Jar 4
    3. total weight is (150 - 5 =) 145 then answer is Jar 5
Problem solved 😀.

Search an element in a row wise and column wise sorted Matrix

Problem: Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:
  • Integers in each row are sorted in ascending from left to right.
  • Integers in each column are sorted in ascending from top to bottom.
Example:

[
  [1,   4,  7],
  [2,   5,  8],
  [3,   6,  9],
]
Given above matrix:
  • Target = 5 return true
  • Target = 11 return false
 
Approach: We need to start with an element where we can clearly decide on which side we should go in case target is less than the current element or greater than the current element.

As given matrix is row wise sorted and column wise sorted. We can start either from Top-Right corner (0, n - 1) or Bottom-Left corner (m - 1, 0). I am taking Top-right corner(row = 0, col = n - 1). Let's see how it works; at every element, there could be three conditions:
  1. Matrix[row][col] == target, we get our answer, return true.
  2. Matrix[row][col] > target, col = col - 1 as we are looking for smaller value
  3. Matrix[row][col] < target, row = row + 1 as we are looking for greater value

Implementation in C#:

        public bool SearchRowSortedAndColSortedMatrix(int[,] matrix, int target)
        {
            int row = 0, col = matrix.GetLength(1) - 1;

            while(row >= 0 && row < matrix.GetLength(0) && col >= 0 && col < matrix.GetLength(1))
            {
                if (matrix[row, col] == target)
                {
                    return true;
                }
                else if (matrix[row, col] > target)
                {
                    --col;
                }
                else
                {
                    ++row;
                }
            }

            return false;
        }


Complexity: O(m + n)

Wednesday, October 28, 2020

[Uber] Sliding Window Maximum

Problem: You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

Example:

Input: nums = [1,2,3,1,4,5,2,7], k = 3
Output: [3,3,4,5,5,7]
Explanation: 
Sliding Window                 Max
---------------               -----
[1  2  3] 1  4  5  2  7         3
 1 [2  3  1] 4  5  2  7         3
 1  2 [3  1  4] 5  2  7         4
 1  2  3 [1  4  5] 2  7         5
 1  2  3  1 [4  5  2] 7         5
 1  2  3  1  4 [5  2  7]        7


Approach: Using Deque of size k. The idea is to store only potential elements of current window of size k. An element is potential if it is in current window and is greater than all other elements on right side of it in current window. In this way if we store elements in deque, we will ensure that the element at front of the deque is the largest and element at back of deque is the smallest of current window.

Here are the steps which we can follow:

  1. Create a deque
  2. Insert first k elements in the deque. Before inserting the element, check if the element at the back of the queue is smaller than the current element, if it is so remove the element from the back of the deque, until all elements left in the deque are greater than the current element. Then insert the current element, at the back of the deque.
  3. Loop from k to n:
    1. Add the front element of the deque to result.
    2. Remove the element from the front of the queue if they are out of the current window.
    3. Insert the next element in the deque. Before inserting the element, check if the element at the back of the queue is smaller than the current element, if it is so remove the element from the back of the deque, until all elements left in the deque are greater than the current element. Then insert the current element, at the back of the deque.
  4. Add the front element of the deque to result to take care of last window.


Implementation in C#:

    public int[] MaxSlidingWindow(int[] nums, int k) 

   {

        if (nums == null)

        {

            return new int[] {};

        }

        if (k > nums.Length)

        {

            return new int[] {Enumerable.Max(nums)};

        }

        LinkedList<int> dequeue = new LinkedList<int>();

        int[] result = new int[nums.Length - k + 1];\

        for (int i = 0; i < k; ++i)

        {

            while (dequeue.Count > 0 && nums[i] >= nums[dequeue.Last.Value])

            {

                dequeue.RemoveLast();

            }

            dequeue.AddLast(i);

        }

        int writeIndex = 0;

        for (int i = k; i < nums.Length; ++i)

        {

            result[writeIndex++] = nums[dequeue.First.Value];

            while (dequeue.Count > 0 && i - dequeue.First.Value + 1 > k)

            {

                dequeue.RemoveFirst();

            }

            while (dequeue.Count > 0 && nums[i] >= nums[dequeue.Last.Value])

            {

                dequeue.RemoveLast();

            }

            dequeue.AddLast(i);

        }

        result[writeIndex] = nums[dequeue.First.Value];

        return result;

    }


Complexity: O(n), although it looked like more but if you look closely at max we are accessing the every element twice; adding and removing from queue. 

Product of Array Except Self

Problem: Given an array nums of n integers,  return an array output such that output[i] is equal to the product of all the elements of nums except nums[i]. Solve it without using division

Example:

Input:  [2, 3, 4, 5]
Output: [60, 40, 30, 24]


Approach: If division was allowed then this problem was straight forward. Calculate the product of all the elements in the array and then divide it by current number:

output[i] =  productOfElement / nums[i]

But given we can't use division, we need to think differently. Let's see what we can do. It is easy to understand that:

Product_Of_All_Elements_Except_Current_Element = Product_Of_All_Elements_Left_Of_Current_Element  * Product_Of_All_Elements_Right_Of_Current_Element

Right! That means if we can calculate Product_Of_All_Elements_Left_Of_Current_Element and Product_Of_All_Elements_Right_Of_Current_Element efficiently, we can calculate Product_Of_All_Elements_Except_Current_Element efficiently. 

If you see these are cumulative calculations. What we can do is have 2 arrays: 

  1. LeftProductArray where LeftProductArray[i] = Prodcuct of nums[0] to nums[i-1] (Product_Of_All_Elements_Left_Of_Current_Element). We can fill this array easily:
    1. LeftProductArray[0] = 1
    2. LeftProductArray[i] = nums[i-1] * LeftProductArray[i-1] // i = 1 to n - 1
  2. RightProductArray where RightProductArray[i] = Prodcuct of nums[i+1] to nums[n-1] (Product_Of_All_Elements_Right_Of_Current_Element). We can fill this array similar to above array easily:
    1. RightProductArray[n-1] = 1
    2. RightProductArray[i] = RightProductArray[i+1] * nums[i+1] // i = n - 2 to 0
Now we can fill our output array easily i.e.

Output[i] = LeftProductArray [i] * RightProductArray[i]

This will work and it will solve our problem in linear time but if you see it is taking extra space. Let's see how we can optimize it:
  1. Instead of taking extra LeftProductArray, we can use Output array itself so in the first loop we will fill Output array instead of LeftProductArray similarly:
    1. Output[0] = 1
    2. Output[i] = Output[i-1] * nums[i-1]
  2. If you see we have already reduced the space by eliminating the use of LeftProductArray but we are still using O(n) extra space. Can we do something about RightProductArray? Yes, if you see all these calculations are cumulative so instead of having an array, we can just use one variable say CurrRightProduct and store the products of right elements in it so our second and final loop will do following steps:
    1. CurrRightProduct = 1
    2. Output[i] = Output[i] * CurrRightProduct // Output[i] already have Product_Of_All_Elements_Left_Of_Current_Element and we are multiplying it will CurrRightProduct which contains Product_Of_All_Elements_Right_Of_Current_Element 
    3. CurrRightProduct = CurrRightProduct * nums[i] // storing this for next iteration which will be for (i - 1)th index.
That's all!
 

Implementation in C#:

        public int[] ProductExceptSelf(int[] nums)

    {
        int length = nums?.Length ?? 0;
        if (length <= 1)
        {
            return nums;
        }
        int[] result = new int[length];
        result[0] = 1;
        for (int i = 1; i < length; ++i)
        {
            result[i] = result[i - 1] * nums[i - 1];
        }
        int rightProduct = 1;
        for (int i = length - 2; i >= 0; --i)
        {
            rightProduct *= nums[i + 1];
            result[i] *= rightProduct;
        }
        return result;
    }


Complexity: O(n)

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.

Approach: We don't have to use bottom-up / Post order traversal approach here like we did in finding LCA of Binary Tree. We can use following property of BST to simplify it:

node.Left.Value < node.Value < node.Right.Value

So we can use top-bottom approach. At each node, we can have one of the following conditions:

  1. Both of the input nodes' values are less than current node value. In this case we just have to go to current node's left and search there.
  2. Both of the input nodes' values are greater than current node value. In this case we just have to go to current node's right and search there.
  3. We got our node


Implementation in C#:

        public new BinaryTreeNode LowestCommonAncestor(BinaryTreeNode p, BinaryTreeNode q)
        {
            if (this.Root == null)
            {
                return null;
            }

            return this.LowestCommonAncestor(this.Root, p, q);
        }

        private new BinaryTreeNode LowestCommonAncestor(BinaryTreeNode node, BinaryTreeNode p, BinaryTreeNode q)
        {
            if (node == null)
            {
                return null;
            }

            if (node.Value < p.Value && node.Value < q.Value)
            {
                return this.LowestCommonAncestor(node.RightNode, p, q);
            }
            else if (node.Value > p.Value && node.Value > q.Value)
            {
                return this.LowestCommonAncestor(node.LeftNode, p, q);
            }
            else
            {
                return node;
            }
        }


Complexity: O(n)

Check if a given linked list is Palindrome or not

Example:

Input: 1->2->3->2->1
Output: true


Approach: We can use a Stack and push all the nodes in it and then we can compare each and every node from head to top of stack and if all nodes values match then we can say the list is palindrome. Basically we are comparing list's reverse with it but it will take O(n) extra space. Let's reduce it:

Go to the middle node of linked list and then reverse all the nodes after the middle element. Now we can compare all the nodes' value from head to middle node's next value (basically the start node of the reversed list). If all matches, we can say the list is palindrome. We can get the middle element in one pass using slow and fast pointer approach which we have used in finding loop in linked list. Let's see using the above example:

1->2->3->2->1

Now 3 is middle element so we will reverse the list 2->1, so now the list will become:

1->2->3->1->2

Now lets say assign 2 iterators one it1 to head and second itr2 to next of middle. Now we will compare all these nodes till itr2 becomes null. You can see it will return true as all the nodes' value actually matches.


Implementation in C#:

        public bool IsPalindrome()

        {

            if (this.Head == null)

            {

                return true;

            }

            // Getting middle element

            LinkedListNode slow = this.Head, fast = this.Head.Next;

            while(fast?.Next != null)

            {

                slow = slow.Next;

                fast = fast.Next;

                if (fast != null)

                {

                    fast = fast.Next;

                }

            }

            // Assigning iterators:

            // 1. itr1 to head

            LinkedListNode itr1 = this.Head;

            // 2. itr2 to next of middle after reversing middle.Next to end of list

            LinkedListNode itr2 = this.ReverseFromNode(slow.Next);

            // Comparing all the nodes

            while(itr2 != null)

            {

                if (itr1.Value != itr2.Value)

                {

                    return false;

                }

                itr1 = itr1.Next;

                itr2 = itr2.Next;

            }

           // All the nodes matched, return true

            return true;

        }


Complexity: O(n)

Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

Example: 

Input: 15
Output: 9
Explanation: Digit 1 occurred in the following numbers: 1, 10, 11, 12, 13, 14 and 15.


Approach: Let's start with a simpler problem: how many digits 1 appearing in all non-negative integers less than or equal to maximum of n-digits length integer?  In other words, how many "1"s in  0-9 (1 digit), how many "1"s in 0-99(2 digits), how many "1"s in 0-999 (3 digits) and so on. 

  • From 0-9, it is easy to find out there is only one "1", it appeared in integer 1.
  • From 0-99, count of "1" can be obtained as follows:
    • Consider two blank slots in which we will fill the numbers: [ ][ ], both slots can take any 1 digit value i.e. 0 to 9. We can denote it as [0-9][0-9]. 
    • Here there are 2 cases which are [0, 2-9][0-9] and [1][0-9]
      • Case 1 - [0, 2-9][0-9]: There is no "1" in the left digit. "1" only appears in the right digit, here is only one "1" in [0-9](We have already calculated that 0-9 has only 1 "1") so for each number in [0, 2-9], we have "1" at its lowest digit. We have 9 different possible highest digits, i.e., 0,2,3,4,5,6,7,8,9, for every one of them, the lowest digit can generate only 1 "1", in total there will be 9 *1 = 9  "1"s in this case.
      • Case 2 - [1][0-9]: "1" is at highest digit, which means every possible number in its lower digits (now is [0-9]) contains one "1" so there are 1*10  = 10 "1"s in this case but we are missing one case of "11" where 1 will be on lowest digit too so there will be 11 "1"s in this case. We can also think [0-9] will also give one "1".
    • Sum of case 1 and case 2 is 20 so there will be 20 "1"s in (0-99).
  • From 0-999, count of "1" can be obtained as follows:
    • Three slots: [][][] with 2 cases [1][0-9][0-9] and [0, 2-9][0-9][0-9]
      • Case 1 - [0, 2-9][0-9][0-9]: We have calculated number of 1s [0-9][0-9] already and there will be no 1 at highest digit in this case so total number of "1"s are 9 * 20 = 180 in this case.
      • Case 2 - [1][0-9][0-9]: Here at the highest digit there will be always "1" so number of 1s are 100-199 i.e. 100 and [0-9][0-9] will produce 20 more "1'"s which we have pre-calculated so total number of "1" are 120 in this case.
    • Sum of case 1 and case 2 is 300 so there will be 300 "1"s in (0-999).
So now if you look closely, you will find a pattern here:

Total_Number_Of_1s(n) = 9 * Total_Number_Of_1s(n - 1) + 10 ^ (n - 1) + Total_Number_Of_1s(n - 1)

Total_Number_Of_1s(n) = 10 * Total_Number_Of_1s(n - 1) +  10 ^(n-1)

where n is equal to number of digit and Total_Number_Of_1s(1) = 1. 

This is all good but it just solve the problem for specific ranges like 0-9 or 0-99 or 0-999 and so on. How to solve this problem for something like 0-n. Let's take an example of n = 2746 and solve it, we will use approximately same strategy here too:  

Total_Number_Of_1s_Random(2746) = Total_Number_Of_1s_Random(0-999) +  Total_Number_Of_1s_Random(1000-2746)

= Total_Number_Of_1s(3) + Total_Number_Of_1s_Random(1000-2746)

= Total_Number_Of_1s(3) +  1000 + Total_Number_Of_1s(3) + Total_Number_Of_1s_Random(2000-2746)

# Number of 1s in 1000 to 1999 will be 1000 (All highest digits will have 1) + Total_Number_Of_1s(3) (number of 1s in 0-999)

= 2 * Total_Number_Of_1s(3) + 1000 + Total_Number_Of_1s_Random(2000-2746)

= 2 * Total_Number_Of_1s(3) + 1000 + Total_Number_Of_1s_Random(0-746) 

# We can ignore highest digit as it will be always 2

= 2 * Total_Number_Of_1s(3) + 1000 + Total_Number_Of_1s(2) + Total_Number_Of_1s_Random(100-746)

= 2 * Total_Number_Of_1s(3) + 1000 + Total_Number_Of_1s(2) + 100 + Total_Number_Of_1s(2) + Total_Number_Of_1s_Random(200-746)

=  2 * Total_Number_Of_1s(3) + 1000 + 2 * Total_Number_Of_1s(2) + 100 + Total_Number_Of_1s_Random(200-746)

= 2 * Total_Number_Of_1s(3) + 1000 + 7 * Total_Number_Of_1s(2) + 100 + Total_Number_Of_1s_Random(0-46)

# For each 2xx, 3xx, 4xx, .. 6xx, we will add more to Total_Number_Of_1s(2) (0-99)

= 2 * Total_Number_Of_1s(3) + 1000 + 7 * Total_Number_Of_1s(2) + 100 + Total_Number_Of_1s(1)  + Total_Number_Of_1s_Random(10-46)

= 2 * Total_Number_Of_1s(3) + 1000 + 7 * Total_Number_Of_1s(2) + 100 + 2 * Total_Number_Of_1s(1)  + 10 + Total_Number_Of_1s_Random(20-46)

= 2 * Total_Number_Of_1s(3) + 1000 + 7 * Total_Number_Of_1s(2) + 100 + 4 * Total_Number_Of_1s(1)  + 10 + Total_Number_Of_1s_Random(40-46)

= 2 * Total_Number_Of_1s(3) + 1000 + 7 * Total_Number_Of_1s(2) + 100 + 4 * Total_Number_Of_1s(1)  + 10 + Total_Number_Of_1s_Random(0-6)

= 2 * 300 + 1000 + 7 * 20 + 100 + 4 * 1 + 10 + 1

= 1855

Hopefully after running through this example the strategy is clear. Basically we go from lowest digit to highest and follow the following steps:
  1. If current digit is 0. Nothing to be added.
  2. If current digit is 1, we add current_digit * Total_Number_Of_1s(position  - 1), number formed lower digits and 1(for 125 => 25 + 1(for 100)).
  3. If current digit is > 1, then we add current_digit * Total_Number_Of_1s(position - 1) and 10 ^ position
* Here position current digit's position from left to right 

Implementation in C#:

        public static int CountDigitOne(int n)
        {
            int result = 0;
            long memory = 0;
            for (long i = 1; i <= n; i = i * 10)
            {
                long d = n % (i * 10) / i; //get the current digit
                result += (int)(d * memory + (d == 1 ? 1 : 0) * (n % i + 1) + (d > 1 ? 1 : 0) * (i));
                memory = memory  * 10 + i; // i here is 10 ^ (digits - 1)
            }
            return result;
        }


Complexity: O(logn)

Tuesday, October 27, 2020

Implement Queue using Stacks

Approach: Using two stacks and a variable say '"front". Here are the algorithms for the queue operations:

  • Enqueue: 
    • IF Stack1.Empty Then front = element
    • Stack1.Push(element)
  • Dequeue:
    • IF Stack2.Empty Then
      • WHILE NOT Stack1.Empty
        • Stack2.Push(Stack1.Pop())
    • Return Stack2.Pop()
  • Peek:
    • IF NOT Stack2.Empty
      • Return Stack2.Peek()
    • Return front
  • Empty:
    • Return Stack1.Empty AND Stack2.Empty


Implementation in C#:

    public class MyQueue

    {
        public MyQueue()
        {
            this.stack1 = new Stack<int>();
            this.stack2 = new Stack<int>();
        }

        public void Enqueue(int x)
        {
            if (this.stack1.Count <= 0)
            {
                this.front = x;
            }

            this.stack1.Push(x);
        }

        public int Dequeue()
        {
            if (this.stack2.Count <= 0)
            {
                while(this.stack1.Count > 0)
                {
                    this.stack2.Push(this.stack1.Pop());
                }
            }

            return this.stack2.Pop();
        }

        public int Peek()
        {
            if(this.stack2.Count > 0)
            {
                return this.stack2.Peek();
            }

            if (this.stack1.Count > 0)
            {
                return this.front;
            }

            return -1;
        }

        public bool Empty()
        {
            return this.stack1.Count <= 0 && this.stack2.Count <= 0;
        }

        int front;
        private Stack<int> stack1;
        private Stack<int> stack2;
    }


Complexity: Pop - O(n) and for rest of operations O(1)

Given an integer, write a method to determine if it is a power of two.

Approach: According to Brian Kernighan algorithm, which we have used in calculating Hamming Weight, subtracting '1' from a number flips all the bits after the rightmost set bit including the rightmost set bit so if a number n is a power of 2 then n & n - 1 will be 0.


Implementation in C#:

        public bool IsPowerOfTwo(int n)

        {

            return n != 0 && n != int.MinValue && (n & n - 1) == 0;

        }


Complexity: O(1)

Monday, October 26, 2020

[Amazon] Majority Element II

Problem: This problem is similar to the previous problem of finding Majority element in the array but here we are trying to find all elements that appear more than n/3 times instead of n/2 elements.

Example:

Input: nums = [6,3,6,5]
Output: [6]


Approach: We are going to use Boyer–Moore majority vote algorithm like we used in previous problem. Important thing here is to consider is like in case of previous problem there could be only one element which can appear more than n/2 times, in this problem there can be maximum two elements which can appear more than n/3 times. Here is the proof:

Say two elements occurred n/3 + num1 and n/3 + num2 times so the total number of times these two elements appeared in array is:

n/3 + num1 + n/3 + num2 = 2n/3 + num1 + num2 

Now you see the third number could appear maximum -

n - (2n/3 + num1 + num2) = n/3 - num1 - num2 

So you can see there can't be a third number which can occur more than n/3 times.


Implementation in C#:

    public IList<int> MajorityElement(int[] nums)
    {
        int length = nums?.Length ?? 0;
        if (length == 0)
        {
            return new List<int>();
        }
        int firstMajor = nums[0];
        int secondMajor = int.MaxValue;
        int count1 = 1, count2 = 0;
        for (int i = 1; i < length; ++i)
        {
            if (nums[i] == firstMajor)
            {
                ++count1;
            }
            else if (nums[i] == secondMajor)
            {
                ++count2;
            }
            else if (count1 == 0)
            {
                firstMajor = nums[i];
                count1 = 1;
            }
            else if (count2 == 0)
            {
                secondMajor = nums[i];
                count2 = 1;
            }
            else
            {
                --count1;
                --count2;
            }
        }
        count1 = 0;
        count2 = 0;
        for (int i = 0; i < length; ++i)
        {
            if (nums[i] == firstMajor)
            {
                ++count1;
            }
            else if (nums[i] == secondMajor)
            {
                ++count2;
            }
        }
        var result = new List<int>();
        if (count1 > length / 3)
        {
            result.Add(firstMajor);
        }
        if (count2 > length / 3)
        {
            result.Add(secondMajor);
        }
        return result;
    }


Complexity: O(n)

Summary Ranges

Problem: You are given a sorted unique integer array. Return the smallest sorted list of ranges that cover all the numbers in the array exactly. That is, each element of input array is covered by exactly one of the ranges, and there is no integer x such that x is in one of the ranges but not in input array.

Each range [a,b] in the list should be output as:

  • "a->b" if a != b
  • "a" if a == b

Example:

Input: nums = [3,4,5,9,12,13]
Output: ["3->5","9","12->13"]
Explanation: The ranges are:
[3, 5] --> "3->5"
[9, 9] --> "9"
[12, 13] --> "12->13"


Approach: Not much to discuss here. Its a straight forward problem. You can easily understand the solution by looking at the code.


Implementation in C#:

        public static IList<string> SummaryRanges(int[] nums)

        {

            List<string> result = new List<string>();

            if (nums?.Length == 0)

            {

                return result;

            }

            string currRange = nums[0].ToString();

            for (int i = 1; i < nums.Length; ++i)

            {

                if (nums[i] > nums[i - 1] + 1)

                {

                    if (int.Parse(currRange) != nums[i - 1])

                    {

                        currRange += $"->{nums[i - 1]}";

                    }

                    result.Add(currRange);

                    currRange = nums[i].ToString();

                }

            }

            if (int.Parse(currRange) != nums[nums.Length - 1])

            {

                currRange += $"->{nums[nums.Length - 1]}";

            }

            result.Add(currRange);           

            return result;

        }


Complexity: O(n)

Calculator II

Problem: This problem is similar to our previous Calculator problem with difference here is the expression string contains only non-negative integers, +, -, *, / operators and empty spaces.

Example:

Input: " 4 *3+5 / 2 "
Output: 14


Approach: We will take the same approach which we have taken in the previous problem. We will use the stack only. We just need to take care of precedence of operators here i.e. '*' and '/' are going to be executed first. 

What we can do is we will keep push operands in stack, if there is a '-' operator we will push "-operand" to stack to take care of subtraction . If we see '*' or '/ ' operator then we apply the operation on top of stack and current number and will push the result to stack.

In the end we will add all the number in the stack and that will be our answer.


Implementation in C#:

        public static int CalculateII(string s)

        {

            if (string.IsNullOrWhiteSpace(s))

            {

                return 0;

            }

            Stack<int> stack = new Stack<int>();

            int operand = 0;

            char operation = '+';

            for (int i = 0; i < s.Length; ++i)

            {

                if (char.IsDigit(s[i]))

                {

                    operand = operand * 10 + (s[i] - '0');

                }

                if ((!char.IsDigit(s[i]) && !char.IsWhiteSpace(s[i])) || i == s.Length - 1)

                {

                    if (operation == '+')

                    {

                        stack.Push(operand);

                    }

                    else if (operation == '-')

                    {

                        stack.Push(-operand);

                    }

                    else if (operation == '*')

                    {

                        int operand1 = stack.Pop();

                        stack.Push(operand1 * operand);

                    }

                    else if (operation == '/')

                    {

                        int operand1 = stack.Pop();

                        stack.Push(operand1 / operand);

                    }

                    operation = s[i];

                    operand = 0;

                }

            }

            int result = 0;

            while (stack.Count > 0)

            {

                result += stack.Pop();

            }

            return result;

        }


Complexity: O(n)