Showing posts with label Microsoft. Show all posts
Showing posts with label Microsoft. Show all posts

Friday, July 26, 2024

[Microsoft][GFG] Tree Boundary Traversal in anticlockwise direction

Problem: Given a Binary Tree, find its Boundary Traversal. The traversal should be in the following order: 

  • Left boundary nodes: defined as the path from the root to the left-most node ie- the leaf node you could reach when you always travel preferring the left subtree over the right subtree. 
  • Leaf nodes: All the leaf nodes except for the ones that are part of left or right boundary.
  • Reverse right boundary nodes: defined as the path from the right-most node to the root. The right-most node is the leaf node you could reach when you always travel preferring the right subtree over the left subtree. Exclude the root from this as it was already included in the traversal of left boundary nodes.

Note: If the root doesn't have a left subtree or right subtree, then the root itself is the left or right boundary. 

Example:

Input:
        1 
      /   \
     2     3  
    / \   / \ 
   4   5 6   7
      / \
     8   9
   
Output: 1 2 4 8 9 6 7 3
Explanation:
Input:
            1
           /
          2
        /  \
       4    9
     /  \    \
    6    5    3
             /  \
            7     8

Output: 1 2 4 6 5 7 8
Explanation:













As you can see we have not taken the right subtree.


Approach: We can solve this problem in four steps given the nature of the problem:

  1. Add root to result.
  2. Preorder traversal of left subtree. If left child is available then do not go for right child. Ignore the leaves.
  3. Inorder traversal of leaves if root is not leaf.
  4. Postorder traversal of right subtre. If right child is available then do not go for left child. Ignore the leaves.
That's all!

Implementation in C#:

class BinaryTreeNode

{

    public BinaryTreeNode Left {get; set;}

    public BinaryTreeNode Right {get; set;}

    public int Value {get; set;}

    public BinaryTreeNode(int val,

                                           BinaryTreeNode left = null,

                                           BinaryTreeNode right = null)

    {

        this.Left = left;

        this.Right = right;

        this.Value = val;

    }

}


class BinaryTree

{

    public List<int> BoundaryTraversal()

    {

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

        if (this.Root == null)

        {

            return result;

        }

        result.Add(this.Root.Value);

        this.TraverseLeftBoundary(this.Root.Left, result);

        // Avoid leaf traversing if root itself is leaf

        if (this.Root.Left != null || this.Root.Right != null)

        {

            this.TraverseLeaves(this.Root, result);

        }

        this.TraverseRightBoundary(this.Root.Right, result);

        return result;

    }

    

    private void TraverseLeftBoundary(BinaryTreeNode node,

                                                              List<int> result)

    {

        if (node == null ||

            (node.Left == null && node.Right == null))

        {

            return;

        }

        if (node.Left != null)

        {

            result.Add(node.Value);

            this.TraverseLeftBoundary(node.Left, result);

        }

        else

        {

            result.Add(node.Value);

            this.TraverseLeftBoundary(node.Right, result);

        }

    }

    

    private void TraverseLeaves(BinaryTreeNode node,

                                                   List<int> result)

    {

        if (node == null)

        {

            return;

        }

        this.TraverseLeaves(node.Left, result);

        if (node.Left == null && node.Right == null)

        {

            result.Add(node.Value);

        }

        this.TraverseLeaves(node.Right, result);

    }

    

    private void TraverseRightBoundary(BinaryTreeNode node,

                                                                List<int> result)

    {

        if (node == null ||

            (node.Left == null && node.Right == null))

        {

            return;

        }

        if (node.Right != null)

        {

            this.TraverseRightBoundary(node.Right, result);

            result.Add(node.Value);

        }

        else

        {

            this.TraverseRightBoundary(node.Left, result);

            result.Add(node.Value);

        }

    }

    public BinaryTreeNode Root {get; set;}

}


Complexity: O(n)

Tuesday, January 24, 2023

[Microsoft][LeetCode] Permutations II

Problem: Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

Example:

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


Approach: This is same question as print permutation of a string but here the input contains duplicates. We are just going to use the same approach of backtracking which we used in the above question but while adding the current permutation to result, we will just check for duplicate. We can use HashSet for it.


Implementation in C#:

    public IList<IList<int>> PermuteUnique(int[] nums)
    {
        List<IList<int>> result = new List<IList<int>>();
        Array.Sort(nums);
        this.PermuteUnique(nums, 0, result, new HashSet<string>());
        return result;
    }

    private void PermuteUnique(int[] nums,
                            int index,
                            IList<IList<int>> result,
                            HashSet<string> set)
    {
        if (index == nums.Length)
        {
            string key = this.GetKey(nums);
            if (set.Add(key))
            {
                result.Add(nums.ToList());
            }
            return;
        }
        for (int j = index; j < nums.Length; ++j)
        {
            this.Swap(nums, index, j);
            this.PermuteUnique(nums, index + 1, result, set);
            this.Swap(nums, index, j);
        }
    }

    private string GetKey(int[] nums)
    {
        return string.Join("-", nums);
    }

    private void Swap(int[] nums, int i, int j)
    {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

Complexity: O(n * !n)

Tuesday, September 21, 2021

[Microsoft][LeetCode] Distinct Subsequences

Problem: Given two strings s and t, return the number of distinct subsequences of s which equals t.

A string's subsequence is a new string formed from the original string by deleting some (can be none) of the characters without disturbing the remaining characters' relative positions. (i.e., "ACE" is a subsequence of "ABCDE" while "AEC" is not).

It is guaranteed the answer fits on a 32-bit signed integer.

Example:

Input: s = "rabbbit", t = "rabbit"
Output: 3
Explanation:
As shown below, there are 3 ways you can generate "rabbit" from S.
rabbbit
rabbbit
rabbbit
Input: s = "babgbag", t = "bag"
Output: 5
Explanation:
As shown below, there are 5 ways you can generate "bag" from S.
babgbag
babgbag
babgbag
babgbag
babgbag


Approach: We are going to use DP here. We are going to maintain a 2D table where Table[i][j] will tell the number of subsequences of s[0...j] of t[0...i]. Obviously Table[Length(t)][Length(s)] will be our answer. Here is how we will fill the table:

  • We take the 2D Table of size Table[Length(t) + 1][Length(s + 1]
  • For all i = 0...Length(s): Table[0][i] = 1 as if t is empty that means for s[0...i] will have exactly 1 number os subsequence which is equal to t.
  • Table[i][j] = 
    • Table[i][j - 1] if t[i - 1] != s[j - 1] 
    • Table[i - 1][j - 1] + Table[i][j - 1] otherwise.

That's all!

 

Implementation in C#:

    public int NumDistinct(string s, string t) 

    {

        int[,] table = new int[t.Length + 1, s.Length + 1];

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

        {

            table[0, i] = 1;

        }

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

        {

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

            {

                if (t[i - 1] == s[j - 1])

                {

                    table[i, j] = table[i - 1, j - 1] + table[i, j - 1];

                }

                else

                {

                    table[i, j] = table[i, j - 1];

                }

            }

        }

        return table[t.Length, s.Length];

    }


Complexity: O(m * n)

Friday, April 9, 2021

[Microsoft Question] Inorder Successor in Binary Search Tree

Problem: Given a binary search tree and a node in it, return the in-order successor of that node in the binary search tree. If the given node has no in-order successor in the tree, return null.

The successor of a node is the node with the smallest value greater than value of the given input node.

Example:



Input: Above tree, input = 6
Output: 8


Approach: We can use the similar approach which we used which we used to set the inorder successor of every node in Binary tree but that will take linear time as we are not using Binary Search Tree's property in this approach.

Let's make the solution efficient by using the BST's property. We can do preorder traversal here. There can be two conditions at every node:

  1. curr_node.Value <= input.Value: In this case we just discard the left subtree of the curr_node.
  2. curr_node.Value > input.Value: In this case we can discard the right subtree of curr_node, but if we see curr_node can also be a candidate of being a inorder successor of the input node.

With this understanding, look at the implementation to understand the whole solution.


Implementation in C#:

    public BinaryTreeNode InorderSuccessor(BinaryTreeNode input) 

    {

        if (this.Root == null)

        {

            return null;

        }

        BinaryTreeNode successor = null;

        BinaryTreeNode node = this.Root;

        while (node != null)

        {

            if (node.Value <= input.Value)

            {

                node = node.RightNode;

            }

            else

            {

                successor = node;

                node = node.LeftNode;

            }

        }

        return successor;

    }


Complexity: O(logn)


Monday, March 15, 2021

[Microsoft Question][LeetCode] Encode and Decode TinyURL

Problem: TinyURL is a URL shortening service where you enter a URL such as https://leetcode.com/problems/design-tinyurl and it returns a short URL such as http://tinyurl.com/4e9iAk.

Design the encode and decode methods for the TinyURL service. There is no restriction on how your encode/decode algorithm should work. You just need to ensure that a URL can be encoded to a tiny URL and the tiny URL can be decoded to the original URL.


Approach: There are many approaches which we can take:

  1. Counter: The problem here is the number of URLs can't be more than int / long range and the codes are predictable.
  2. Random number: Problem here is again the number of URLs can't be more than int / long range and also collision can happen so encryption performance can be degraded.

Now our final approach is to generate random fixed length (say length = 6) and assign it to url while encrypting. The number of URLs can be generated using this approach is 62 ^ 6 which is very large number. We can increase the length if we want more URLs. 

Prediction of next code and collision are highly unlikely. 


Implementation in C#:

public class Codec 

{

    private const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    private const int tinyUrlSize = 6;

    private const string tinyUrlPrefix = "http://tinyurl.com/";

    

    public string encode(string longUrl) 

    {    

        Random random = new Random();

        while(true)

        {

            string tinyUrl = string.Empty;

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

            {

                tinyUrl += chars[random.Next(chars.Length)];

            }

            if (!urlMap.ContainsKey(tinyUrl))

            {

                urlMap[tinyUrl] = longUrl;

                return tinyUrlPrefix + tinyUrl;

            }

        }

    }


    public string decode(string shortUrl) 

    {    

        string key = shortUrl.Substring(tinyUrlPrefix.Length);

        if (!urlMap.ContainsKey(key))

        {

            return string.Empty;

        }

        return urlMap[key];

    }

    Dictionary<string, string> urlMap = new Dictionary<string, string>();

}


Complexity: O(length of chars)

Thursday, March 4, 2021

[Microsoft Question][LeetCode] Remove Comments

Problem: Given a C++ program, remove comments from it. The program source is an array where source[i] is the i-th line of the source code. This represents the result of splitting the original source code string by the newline character \n.

In C++, there are two types of comments, line comments, and block comments.

The string // denotes a line comment, which represents that it and rest of the characters to the right of it in the same line should be ignored.

The string /* denotes a block comment, which represents that all characters until the next (non-overlapping) occurrence of */ should be ignored. (Here, occurrences happen in reading order: line by line from left to right.) To be clear, the string /*/ does not yet end the block comment, as the ending would be overlapping the beginning.

The first effective comment takes precedence over others: if the string // occurs in a block comment, it is ignored. Similarly, if the string /* occurs in a line or block comment, it is also ignored.

If a certain line of code is empty after removing comments, you must not output that line: each string in the answer list will be non-empty.

There will be no control characters, single quote, or double quote characters. For example, source = "string s = "/* Not a comment. */";" will not be a test case. (Also, nothing else such as defines or macros will interfere with the comments.)

It is guaranteed that every open block comment will eventually be closed, so /* outside of a line or block comment always starts a new comment.

Finally, implicit newline characters can be deleted by block comments. Please see the examples below for details.

After removing the comments from the source code, return the source code in the same format.

Example:

Input: 
source = ["/*Test program */", "int main()", "{ ", "  // variable declaration ", "int a, b, c;", "/* This is a test", "   multiline  ", "   comment for ", "   testing */", "a = b + c;", "}"]

The line by line code is visualized as below:
/*Test program */
int main()
{ 
  // variable declaration 
int a, b, c;
/* This is a test
   multiline  
   comment for 
   testing */
a = b + c;
}

Output: ["int main()","{ ","  ","int a, b, c;","a = b + c;","}"]

The line by line code is visualized as below:
int main()
{ 
  
int a, b, c;
a = b + c;
}

Explanation: 
The string /* denotes a block comment, including line 1 and lines 6-9. The string // denotes line 4 as comments.
Input: 
source = ["a/*comment", "line", "more_comment*/b"]
Output: ["ab"]
Explanation: The original source string is "a/*comment\nline\nmore_comment*/b", where we have bolded the newline characters.  After deletion, the implicit newline characters are deleted, leaving the string "ab", which when delimited by newline characters becomes ["ab"].


Approach: We just parse the string and remove all the commented text. The only thing which is special here is block comment so basically we have two states here one is if current text is in block comment and second is when not in block comment. 

You can just look at the implementation to understand the approach.


Implementation in C#:

    public IList<string> RemoveComments(string[] source) 

    {

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

        bool lookForCloseComment = false;

        StringBuilder newLineBuilder = new StringBuilder();

        foreach (string line in source)

        {

            int i = 0;

            if (!lookForCloseComment)

            {

                newLineBuilder = new StringBuilder();

            }

            while (i < line.Length)

            {

                if (lookForCloseComment)

                {

                    if (i + 1 < line.Length && line[i] == '*' && line[i + 1] == '/')

                    {

                        lookForCloseComment = false;

                        ++i;

                    }

                }

                else

                {

                    if (i + 1 < line.Length && line[i] == '/' && line[i + 1] == '*')

                    {

                        lookForCloseComment = true;

                        ++i;

                    }

                    else if (i + 1 < line.Length && line[i] == '/' && line[i + 1] == '/')

                    {

                        break;

                    }

                    else

                    {

                        newLineBuilder.Append(line[i]);

                    }

                }

                ++i;

            }

            if (!lookForCloseComment && newLineBuilder.Length > 0)

            {

                result.Add(newLineBuilder.ToString());

            }

        }

        return result;

    }


Complexity: O(n) where n is the number of characters in the input string array.

Tuesday, March 2, 2021

[Microsoft Question][LeetCode] Replace All ?'s to Avoid Consecutive Repeating Characters

Problem: Given a string s containing only lower case English letters and the '?' character, convert all the '?' characters into lower case letters such that the final string does not contain any consecutive repeating characters. You cannot modify the non '?' characters.

It is guaranteed that there are no consecutive repeating characters in the given string except for '?'.

Return the final string after all the conversions (possibly zero) have been made. If there is more than one solution, return any of them. It can be shown that an answer is always possible with the given constraints.

Example:

Input: s = "?zs"
Output: "azs"
Explanation: There are 25 solutions for this problem. From "azs" to "yzs", all are valid. Only "z" is an invalid modification as the string will consist of consecutive repeating characters in "zzs".
Input: s = "ubv?w"
Output: "ubvaw"
Explanation: There are 24 solutions for this problem. Only "v" and "w" are invalid modifications as the strings will consist of consecutive repeating characters in "ubvvw" and "ubvww".
Input: s = "j?qg??b"
Output: "jaqgacb"
Input: s = "??yw?ipkj?"
Output: "acywaipkja"


Approach: Nothing to explain here as it is a straight forward problem to solve. Have a look at implementation directly to understand the solution.


Implementation in C#:

    public string ModifyString(string s) 

    {

        if (s?.Length == 0)

        {

            return s;

        }

        if (s.Length == 1)

        {

            return s[0] != '?' ? s : "a";

        }

        char[] sArr = s.ToCharArray();

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

        {

            if (sArr[i] == '?')

            {

                char targetChar = 'a';

                if (i > 0 && i < sArr.Length - 1)

                {

                    targetChar = sArr[i - 1] == 'z' || sArr[i - 1] == '?' ? 'a' : (char)(sArr[i - 1] + 1);

                    if (targetChar == sArr[i + 1])

                    {

                        targetChar = targetChar == 'z' ? 'a' : (char)(targetChar + 1);

                    }

                }

                else if (i == 0)

                {

                    targetChar = sArr[i + 1] == 'z' || sArr[i + 1] == '?' ? 'a' : (char)(sArr[i + 1] + 1);

                }

                else if (i == sArr.Length - 1)

                {

                    targetChar = sArr[i - 1] == 'z' || sArr[i - 1] == '?' ? 'a' : (char)(sArr[i - 1] + 1);

                }

                sArr[i] = targetChar;

            }

        }

        return new string(sArr);

    }


Complexity: O(n)

Thursday, February 25, 2021

[Microsoft Question] Shortest Unsorted Continuous Subarray

Problem: Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order.

Return the shortest such subarray and output its length.

Example:

Input: nums = [2,3,1,4,5]
Output: 3
Explanation: You need to sort [2,3,1] in ascending order to make the whole array sorted in ascending order.


Approach: The intuition is that the correct position of the minimum element in the unsorted subarray is the required left boundary. Similarly, the correct position of the maximum element in the unsorted subarray is the required right boundary.

One way to achieve it is first we create a copy of the original array say sortedNums and then sort it. Now for every i = 0 to n - 1 whenever we find num[i] != sortedNums[i] first time we know that this is the minimum element which is not in correct order so we mark 'i' as the left boundary. 

To get the right boundary, we could parse in reverse order i.e. i = n - 1 to 0 and whenever we find num[i] != sortedNums[i] first time we know that this is the maximum element which is not in correct order so we mark 'i' as the right boundary. Now we can return right - left + 1.

This approach will work but it will take O(nlogn) time for sorting. Let's try to do better; Can we find the min and max element of unsorted subarray without sorting? Once we find the min and max element, its easy to find the indexes where these min and max should be placed.

Let's see how to find the min number in the unsorted subarray. For every i = 1 to n - 1 whenever we find that nums[i] < nums[i - 1] that mean at 'i' unsorted subarray is started and now we can find the min of subarray nums[i...n-1] which is our minimum number.

Similarly, to get the max number we can have a loop from i = n - 2 to 0 and whenever we find nums[i] > nums[i + 1] that means we get the end of unsorted subarray. Now we can find the max of subarray nums[0...i] and which will tell us the maximum number of the unsorted subarray.

Now we just traverse the array from i = 0 to n - 1 and whenever we see that nums[i] > min then we know that this is the right position for min and hence 'i' is our left boundary. Similarly we traverse the array in reverse order i.e. j = n - 1 to 0 and whenever we find that nums[j] < max then we can say 'j' is our right boundary. Now we can return right - left + 1.

That's all!


Implementation in C#:

Approach 1: With Sorting:

    public int FindUnsortedSubarray(int[] nums) 

    {

        int[] sortedNums = (int[]) nums.Clone();

        Array.Sort(sortedNums);

        int left = -1, right = 0;

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

        {

            if (nums[i] != sortedNums[i])

            {

                left = i;

                break;

            }

        }

        // Already sorted

        if (left == -1)

        {

            return 0;

        }        

        for (int i = nums.Length - 1; i >= 0; --i)

        {

            if (nums[i] != sortedNums[i])

            {

                right = i;

                break;

            }

        }        

        return right - left + 1; 

    }


Approach 2: Without Sorting:

    public int FindUnsortedSubarray(int[] nums) 

    {

        int min = int.MaxValue, max = int.MinValue;

        bool isSorted = true;

        int len = nums.Length;

        for (int i = 1; i < len; ++i)

        {

            if (nums[i] < nums[i - 1])

            {

                isSorted = false;

            }  

            if (!isSorted)

            {

                min = Math.Min(min, nums[i]);

            }

        }

        if (isSorted)

        {

            return 0;

        }

        isSorted = true;

        for (int i = len - 2; i >= 0; --i)

        {

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

            {

                isSorted = false;

            }

            if (!isSorted)

            {

                max = Math.Max(max, nums[i]);

            }

        }

        int left = 0, right = len - 1;

        for (; left < len; ++left)

        {

            if (nums[left] > min)

            {

                break;

            }

        }   

        for (; right >= 0; --right)

        {

            if (nums[right] < max)

            {

                break;

            }

        }        

        return right - left + 1;

    }


Complexity: Approach 1: O(nlogn), Approach 2: O(n)

Friday, January 8, 2021

[Amazon][Microsoft] Design Data Structure with Insert, Delete, GetRandom at O(1)

Problem: Implement the RandomizedSet class:

  • bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise.
  • bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise.
  • int getRandom() Returns a random element from the current set of elements (it's guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.


Approach: We can use hash and array combination here. In the hash val will be the key and value is the index at which we put the val in the array. Here are the algorithm for each operation:

  1. Insert: 
    • Check if val is in hash or not, if yes, then return false.
    • Insert val at the end of array
    • Make an entry in hash: hash[val] = Length of array - 1 
  2. Remove:
    • Check if val is in hash or not, if not, then return false.
    • Copy the last element of array to hash[val]. Basically overwrite val with last element of array.
    • Update hash with hash[last element of array] = hash[val]
    • Remove the last element.
  3. GetRandom:
    • Return element from array at any random index.


Implementation in C#:

public class RandomizedSet
{
    public RandomizedSet()
    {
        this.map = new Dictionary<int, int>();
        this.list = new List<int>();
    }
   
    public bool Insert(int val)
    {
        if (this.map.ContainsKey(val))
        {
            return false;
        }
        this.list.Add(val);
        this.map[val] = this.list.Count - 1;
        return true;
    }
   
    public bool Remove(int val)
    {
        if (!this.map.ContainsKey(val))
        {
            return false;
        }
        int valIndex = this.map[val];
        this.list[valIndex] = this.list[this.list.Count - 1];
        this.map[this.list[valIndex]] = valIndex;
        this.list.RemoveAt(this.list.Count - 1);
        this.map.Remove(val);
        return true;
    }
   
    public int GetRandom()
    {
        return this.list[new Random().Next() % this.list.Count];
    }

    private Dictionary<int, int> map;
    private List<int> list;
}


Complexity: O(1) for all three operations.

Friday, October 9, 2020

Microsoft Question: House Robber II

Problem: It is same as previous House Robber problem except here we have one more condition:

  • All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. 
Example:

Input: nums = [5,8,6]
Output: 8
Explanation: You cannot rob house 1 (money = 5) and then rob house 3 (money = 6), because they are adjacent houses.


Approach: We will have the same approach as our previous problem with one difference. Here we are going to have two tables instead of one table. One table will store the max money excluding last house and second will store the max money excluding first house. We will fill the Tables in same way we did it in previous problem. 

   IF i != 2
    TableWithLastHouse[i] = MAX(TableWithLastHouse[i - 1], TableWithLastHouse[i - 2] + nums[i]   
   ELSE IF i != nums.Length - 1
     TableWithFirstHouse[i] = Math.Max(TableWithFirstHouse[i - 1], TableWithFirstHouse[i - 2] + nums[i])

Ultimately we will take the maximum of TableWithFirstHouse[n - 2] and TableWithLastHouse[n - 1]. 

We can use the same strategy of having 4 variables; 2 variables per table instead of having Tables.


Implementation in C#:

        public static int RobII(int[] nums)
        {
            if (nums?.Length == 0)
            {
                return 0;
            }

            if (nums.Length == 1)
            {
                return nums[0];
            }

            if (nums.Length == 2) 
            {
                return Math.Max(nums[0], nums[1]);
            }

            int prevMaxWithFirstHouse = nums[0]; // Won't include the last house
            int currMaxWithFirstHouse = Math.Max(nums[0], nums[1]);
            int prevMaxWithLastHouse = nums[1]; // Won't include the first house
            int currMaxWithLastHouse = Math.Max(nums[1], nums[2]);

            for (int i = 2; i < nums.Length; ++i)
            {
                if (i != 2)
                {
                    int temp = currMaxWithLastHouse;
                    currMaxWithLastHouse = Math.Max(currMaxWithLastHouse, prevMaxWithLastHouse + nums[i]);
                    prevMaxWithLastHouse = temp;
                }
                if (i != nums.Length - 1)
                {
                    int temp = currMaxWithFirstHouse;
                    currMaxWithFirstHouse = Math.Max(currMaxWithFirstHouse, prevMaxWithFirstHouse + nums[i]);
                    prevMaxWithFirstHouse = temp;
                }
            }

            return Math.Max(currMaxWithFirstHouse, currMaxWithLastHouse);
        }


Complexity: O(n)

Tuesday, September 29, 2020

[Microsoft][LeetCode] Dungeon Game

Problem: The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

Write a function to determine the knight's minimum initial health so that he is able to rescue the princess. Here are few points to be considered -

  • The knight's health has no upper bound.
  • Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.

Example: given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

-2 (K)-33
-5-101
1030-5 (P)


Approach: Use DP. We can maintain a 2D table where Table[i][j] will tell the minimum health points required to reach (m - 1, n - 1), where m is number of rows and n is number of columns, from (i, j). Obviously our answer will be Table[0][0]. Here is how we will fill the table:

  1. Table[m - 1][n - 1] = Max (1 - Matrix[m - 1][n - 1], 1) // At least1 is required
  2. Foreach i from m - 1 to 0 and j from n - 1 to 0: 
            Table[i][j] = Max ( Min (Table[i + 1][j], Table[i][j + 1]) - Matrix[i][j], 1)

Please note that in above statement, you have to take care of boundary conditions.


Implementation in C#:

        public int CalculateMinimumHP(int[][] dungeon)

        {

            int[,] minHealthHP = new int[dungeon.Length, dungeon[0].Length];

            minHealthHP[dungeon.Length - 1, dungeon[0].Length - 1] = Math.Max(1 - dungeon[dungeon.Length - 1][dungeon[0].Length - 1], 1);

            for (int i = dungeon.Length - 2; i >= 0; --i)

            {

                minHealthHP[i, dungeon[0].Length - 1] = Math.Max(minHealthHP[i + 1, dungeon[0].Length - 1] - dungeon[i][dungeon[0].Length - 1], 1);

            }

            for (int i = dungeon[0].Length - 2; i >= 0; --i)

            {

                minHealthHP[dungeon.Length - 1, i] = Math.Max(minHealthHP[dungeon.Length - 1, i + 1] - dungeon[dungeon.Length -1][i], 1);

            }

            for (int i = dungeon.Length - 2; i >= 0; --i)

            {

                for (int j = dungeon[0].Length - 2; j >= 0; --j)

                {

                    minHealthHP[i, j] = Math.Max(Math.Min(minHealthHP[i + 1, j], minHealthHP[i, j + 1]) - dungeon[i][j], 1);

                }

            }

            return minHealthHP[0, 0];

        }


Complexity: O(m * n) => O(n^2)

Thursday, September 10, 2020

[LeetCode] Populating Next Right Pointers in Each Node II

Problem: Given a binary tree

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Example:

Input: root = [1,2,3,4,5,null,7]
Output: [1,#,2,3,#,4,5,7,#]
Explanation: Given the above binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B. The serialized output is in level order as connected by the next pointers, with '#' signifying the end of each level.
Input: root = []
Output: []


Approach: We can use Level Order traversal to solve this problem easily and we can use Pre order traversal too but these approaches will take at least O(logn) space.

What we can use is the next pointer itself. We will use kind of level order traversal only but think if before going to next level if we have set the next pointer for the next level already then we will just use the starting node of the level and then we can traverse the whole level using the next pointer.

With this intuition, you can just look at the implementation to understand all the steps.


Implementation in C#:

    public Node Connect(Node root)
    {
        if (root == null)
        {
            return root;
        }
        Node levelStartNode = root;
        while (levelStartNode != null)
        {
            Node currNode = levelStartNode;
            Node prevNode = null;
            levelStartNode = null;
            while (currNode != null)
            {
                if (currNode.left != null)
                {
                    this.UpdateNextNode(currNode.left,
                                    ref prevNode,
                                    ref levelStartNode);
                }
                if (currNode.right != null)
                {
                    this.UpdateNextNode(currNode.right,
                                    ref prevNode,
                                    ref levelStartNode);
                }
                currNode = currNode.next;
            }
        }
        return root;
    }

    private void UpdateNextNode(
                            Node node,
                            ref Node prevNode,
                            ref Node levelStartNode)
    {
        if (prevNode != null)
        {
            prevNode.next = node;
            prevNode = node;
        }
        else
        {
            prevNode = node;
            levelStartNode = node;
        }
    }


Complexity: O(n)

Thursday, September 3, 2020

[Microsoft][LeetCode] Next Permutation

Problem: A permutation of an array of integers is an arrangement of its members into a sequence or linear order.

  • For example, for arr = [1,2,3], the following are all the permutations of arr: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1].

The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).

  • For example, the next permutation of arr = [1,2,3] is [1,3,2].
  • Similarly, the next permutation of arr = [2,3,1] is [3,1,2].
  • While the next permutation of arr = [3,2,1] is [1,2,3] because [3,2,1] does not have a lexicographical larger rearrangement.

Given an array of integers nums, find the next permutation of nums.

The replacement must be in place and use only constant extra memory.

Example:

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

Approach: The approach which we are using here is mention on wikipedia. Here are the steps:

  • Find the first number which is not in descending order. say at index i
  • Find the number which is just bigger than the number found at step 1. Say at index j. Swap arr[i] and arr[j].
  • Reverse the array from i + 1 to array's length.


Implementation in C#:

    public void NextPermutation(int[] nums)
    {
        int length = nums?.Length ?? 0;
        if (length <= 1)
        {
            return;
        }
        int i = length - 1;
        while (i > 0 && nums[i] <= nums[i - 1])
        {
            i--;
        }
        if (i > 0)
        {
            int j = length - 1;
            while (j > i - 1 && nums[i - 1] >= nums[j])
            {
                --j;
            }
            this.Swap(nums, i - 1, j);
        }
        this.Reverse(nums, i);
    }

    private void Swap(int[] nums, int i, int j)
    {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    private void Reverse(int[] nums, int start)
    {
        int end = nums.Length - 1;
        while (start < end)
        {
            this.Swap(nums, start++, end--);
        }
    }


Complexity: O(n)