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)

Monday, January 23, 2023

[LeetCode] Find the Town Judge

Problem: In a town, there are n people labeled from 1 to n. There is a rumor that one of these people is secretly the town judge.

If the town judge exists, then:

  • The town judge trusts nobody.
  • Everybody (except for the town judge) trusts the town judge.
  • There is exactly one person that satisfies properties 1 and 2.

You are given an array trust where trust[i] = [ai, bi] representing that the person labeled ai trusts the person labeled bi.

Return the label of the town judge if the town judge exists and can be identified, or return -1 otherwise.

Example:

Input: n = 2, trust = [[1,2]]
Output: 2
Input: n = 3, trust = [[1,3],[2,3]]
Output: 3
Input: n = 3, trust = [[1,3],[2,3],[3,1]]
Output: -1


Approach: This is a straight forward problem. We can use Hash map to solve this problem. Simply, have a look at the implementation to understand the solution.


Implementation in C#:

    public int FindJudge(int n, int[][] trust)
    {
        if (n == 1 && trust.Length == 0)
        {
            return 1;
        }
        Dictionary<int, List<int>> trustGraph = new Dictionary<int, List<int>>();
        HashSet<int> personsWhoTrust = new HashSet<int>();
        foreach(int[] t in trust)
        {
            if (!trustGraph.ContainsKey(t[1]))
            {
                trustGraph[t[1]] = new List<int>();
            }
            trustGraph[t[1]].Add(t[0]);
            personsWhoTrust.Add(t[0]);
        }
        for (int i = 1; i <= n; ++i)
        {
            if (trustGraph.ContainsKey(i))
            {
                if (trustGraph[i].Count == n - 1 && !personsWhoTrust.Contains(i))
                {
                    return i;
                }
            }
        }
        return -1;
    }

Complexity: O(n)


Friday, January 13, 2023

[LeetCode] Longest Path With Different Adjacent Characters

Problem: You are given a tree (i.e. a connected, undirected graph that has no cycles) rooted at node 0 consisting of n nodes numbered from 0 to n - 1. The tree is represented by a 0-indexed array parent of size n, where parent[i] is the parent of node i. Since node 0 is the root, parent[0] == -1.

You are also given a string s of length n, where s[i] is the character assigned to node i.

Return the length of the longest path in the tree such that no pair of adjacent nodes on the path have the same character assigned to them.

Example:

Input: parent = [-1,0,0,1,1,2], s = "abacbe"
Output: 3
Explanation: The longest path where each two adjacent nodes have different characters in the tree is the path: 0 -> 1 -> 3. The length of this path is 3, so 3 is returned.
It can be proven that there is no longer path that satisfies the conditions. 

Input: parent = [-1,0,0,0], s = "aabc"
Output: 3
Explanation: The longest path where each two adjacent nodes have different characters is the path: 2 -> 0 -> 3. The length of this path is 3, so 3 is returned.


Approach: This is again a PostOrder Traversal kind of problem as here too if the subtrees are processed before the root of the subtree then we can easily do the calculation at the root.

At any node, the longest Path will be - 

Max (Largest Path Chain among node's children where character at node is different than child node's character + Second Largest Path Chain among node's children where character at node is different than child node's character + 1(node itself), Largest Path among where node's character is same as child's character)

Why we are taking just one chain in case of inclusion of node because we just can't have branches when we are including the current node. See the below example:

                  a

       /

      b

             / \

           c    d

Here if we include 'a' the path could be a->b->c or a->b->d.

We can have longestPath as global / reference variable to record the longesPath and we can return the longest chain + 1(including current node) from the PostOrderTraversal method as only the longest chain is useful for the parent node.


Implementation in C#:

    public int LongestPath(int[] parent, string s)
    {
        var tree = this.MakeTree(parent);
        int longestPath = 1;
        this.LongestPathPostOrder(0, tree, s, ref longestPath);
        return longestPath;
    }

    private int LongestPathPostOrder(
                                int node,
                                Dictionary<int, List<int>> tree,
                                string s,
                                ref int longestPath)
    {
        int longestPathLength = 0, secondLongestLength = 0;
        if (!tree.ContainsKey(node))
        {
            return 1;
        }
        foreach (int child in tree[node])
        {
            int pathLength = this.LongestPathPostOrder(
                                                    child,
                                                    tree,
                                                    s,
                                                    ref longestPath);
            if (s[child] == s[node])
            {
                continue;
            }
            else
            {
                if (pathLength > longestPathLength)
                {
                    secondLongestLength = longestPathLength;
                    longestPathLength = pathLength;    
                }
                else if (pathLength > secondLongestLength)
                {
                    secondLongestLength = pathLength;
                }
            }
        }
       
        longestPath = Math.Max(
                        longestPath,
                        1 + longestPathLength + secondLongestLength);
        return longestPathLength + 1;
    }

    private Dictionary<int, List<int>> MakeTree(int[] parent)
    {
        var tree = new Dictionary<int, List<int>>();
        for (int i = 1; i < parent.Length; ++i)
        {
            if (!tree.ContainsKey(parent[i]))
            {
                tree[parent[i]] = new List<int>();
            }
            tree[parent[i]].Add(i);
        }
        return tree;
    }

Complexity: O(n)

Thursday, January 12, 2023

[LeetCode] Shortest Path in a Grid with Obstacles Elimination

Problem: You are given an m x n integer matrix grid where each cell is either 0 (empty) or 1 (obstacle). You can move up, down, left, or right from and to an empty cell in one step.

Return the minimum number of steps to walk from the upper left corner (0, 0) to the lower right corner (m - 1, n - 1) given that you can eliminate at most k obstacles. If it is not possible to find such walk return -1.

Example:

Input: grid = [[0,0,0],[1,1,0],[0,0,0],[0,1,1],[0,0,0]], k = 1
Output: 6
Explanation: 
The shortest path without eliminating any obstacle is 10.
The shortest path with one obstacle elimination at position (3,2) is 6. Such path is (0,0) -> (0,1) -> (0,2) -> (1,2) -> (2,2) -> (3,2) -> (4,2).

Input: grid = [[0,1,1],[1,1,1],[1,0,0]], k = 1
Output: -1
Explanation: We need to eliminate at least two obstacles to find such a walk.


Approach: This is again a BSF problem but here the next state/node is just not the neighbor cells but with that the number of obstacles removed is also part of next state so the edge is (x, y, number of obstacles removed).

That's all! 


Implementation in C#:

public class QueueData
{
    public int X {get; set;}
    public int Y {get; set;}
    public int Obstacles {get; set;}
    public QueueData(int x, int y, int obs)
    {
        this.X = x;
        this.Y = y;
        this.Obstacles = obs;
    }
}

public class Solution
{
    public int ShortestPath(int[][] grid, int k)
    {
        int rows = grid?.Length ?? 0;
        if(rows == 0)
        {
            return 0;
        }
        int cols = grid[0].Length;
        if (k == 0 && grid[0][0] == 1)
        {
            return -1;
        }
        bool[,,] visited = new bool[rows, cols, k + 1];
        Queue<QueueData> queue = new Queue<QueueData>();
        int obstacle = grid[0][0] == 1 ? 1 : 0;
        queue.Enqueue(new QueueData(0, 0, obstacle));
        visited[0, 0, obstacle] = true;
        int steps = 0;
        while(queue.Count > 0)
        {
            int size = queue.Count;
            for (int i = 0; i < size; ++i)
            {
                var queueData = queue.Dequeue();
                if (queueData.X == rows - 1 &&
                    queueData.Y == cols - 1)
                {
                    return steps;
                }

                this.AddValidNeighboursToQueue(
                                            grid,
                                            queue,
                                            queueData,
                                            visited,
                                            k);
            }
            ++steps;
        }
        return -1;
    }

    private void AddValidNeighboursToQueue(
                            int[][] grid,
                            Queue<QueueData> queue,
                            QueueData data,
                            bool[,,] visited,
                            int maxObstacles)
    {
        int x = data.X;
        int y = data.Y;
        int obstacles = data.Obstacles;
        if (this.IsValidCell(grid, x - 1, y))
        {
            this.AddCellToQueueIfPossible(grid,
                                        queue,
                                        x - 1,
                                        y,
                                        obstacles,
                                        maxObstacles,
                                        visited);
        }
        if (this.IsValidCell(grid, x + 1, y))
        {
            this.AddCellToQueueIfPossible(grid,
                                        queue,
                                        x + 1,
                                        y,
                                        obstacles,
                                        maxObstacles,
                                        visited);
        }
        if (this.IsValidCell(grid, x, y - 1))
        {
            this.AddCellToQueueIfPossible(grid,
                                        queue,
                                        x,
                                        y - 1,
                                        obstacles,
                                        maxObstacles,
                                        visited);
        }
        if (this.IsValidCell(grid, x, y + 1))
        {
            this.AddCellToQueueIfPossible(grid,
                                        queue,
                                        x,
                                        y + 1,
                                        obstacles,
                                        maxObstacles,
                                        visited);
        }
    }

    private void AddCellToQueueIfPossible(
                                int[][] grid,
                                Queue<QueueData> queue,
                                int x,
                                int y,
                                int obstacles,
                                int maxObstacles,
                                bool[,,] visited)
    {
        if (grid[x][y] == 1)
        {
            ++obstacles;
        }
        if (obstacles <= maxObstacles && !visited[x, y, obstacles])
        {
            visited[x, y, obstacles] = true;
            queue.Enqueue(new QueueData(x, y, obstacles));
        }
    }

    private bool IsValidCell(int[][] grid, int x, int y)
    {
        return x >= 0 &&
            x < grid.Length &&
            y >= 0 &&
            y < grid[0].Length;
    }
}

Complexity: O(n^2)

[LeetCode] Number of Nodes in the Sub-Tree With the Same Label

Problem: You are given a tree (i.e. a connected, undirected graph that has no cycles) consisting of n nodes numbered from 0 to n - 1 and exactly n - 1 edges. The root of the tree is the node 0, and each node of the tree has a label which is a lower-case character given in the string labels (i.e. The node with the number i has the label labels[i]).

The edges array is given on the form edges[i] = [ai, bi], which means there is an edge between nodes ai and bi in the tree.

Return an array of size n where ans[i] is the number of nodes in the subtree of the ith node which have the same label as node i.

A subtree of a tree T is the tree consisting of a node in T and all of its descendant nodes.

Example:

Input: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = "abaedcd"
Output: [2,1,1,1,1,1,1]
Explanation: Node 0 has label 'a' and its sub-tree has node 2 with label 'a' as well, thus the answer is 2. Notice that any node is part of its sub-tree.
Node 1 has a label 'b'. The sub-tree of node 1 contains nodes 1,4 and 5, as nodes 4 and 5 have different labels than node 1, the answer is just 1 (the node itself).

Input: n = 4, edges = [[0,1],[1,2],[0,3]], labels = "bbbb"
Output: [4,2,1,1]
Explanation: The sub-tree of node 2 contains only node 2, so the answer is 1.
The sub-tree of node 3 contains only node 3, so the answer is 1.
The sub-tree of node 1 contains nodes 1 and 2, both have label 'b', thus the answer is 2.
The sub-tree of node 0 contains nodes 0, 1, 2 and 3, all with label 'b', thus the answer is 4.

Input: n = 5, edges = [[0,1],[0,2],[1,3],[0,4]], labels = "aabab"
Output: [3,2,1,1,1]

Constraints:

  • 1 <= n <= 105
  • edges.length == n - 1
  • edges[i].length == 2
  • 0 <= ai, bi < n
  • ai != bi
  • labels.length == n
  • labels is consisting of only of lowercase English letters.

Approach: We can use PostOrder traversal here as it visits the whole subtree before visiting the root of the subtree. Given it's an undirected graph, we just need to take care that we don't visit the same node more than once so we can use a visit set to avoid it.


Implementation in C#:

    public int[] CountSubTrees(int n, int[][] edges, string labels)
    {
        if (n == 0)
        {
            return new int[] {};
        }
        int length = edges?.Length ?? 0;
        int[] result = new int[n];
        if (length == 0)
        {
            return result;
        }
        var tree = this.MakeTree(edges);
        bool[] visited = new bool[n];
        this.CountSubTreesPostOrder(0, tree, visited, labels, result);
        return result;
    }

    private int[] CountSubTreesPostOrder(
                    int node,
                    Dictionary<int, List<int>> tree,
                    bool[] visited,
                    string labels,
                    int[] result)
    {
        int[] labelCountMap = new int[26];
        visited[node] = true;
        if (tree.ContainsKey(node))
        {
            foreach (int child in tree[node])
            {
                if (!visited[child])
                {
                    int[] childLabelCountMap = this.CountSubTreesPostOrder(
                                                child,
                                                tree,
                                                visited,
                                                labels,
                                                result);
                    for (int i = 0; i < 26; ++i)
                    {
                        labelCountMap[i] += childLabelCountMap[i];
                    }
                }
            }
        }
        result[node] = ++labelCountMap[labels[node] - 'a'];
        return labelCountMap;
    }

    private Dictionary<int, List<int>> MakeTree(int[][] edges)
    {
        var nodesMap = new Dictionary<int, List<int>>();
        foreach(int[] edge in edges)
        {
            if (!nodesMap.ContainsKey(edge[0]))
            {
                nodesMap[edge[0]] = new List<int>();
            }
            if (!nodesMap.ContainsKey(edge[1]))
            {
                nodesMap[edge[1]] = new List<int>();
            }
            nodesMap[edge[0]].Add(edge[1]);
            nodesMap[edge[1]].Add(edge[0]);
        }
        return nodesMap;
    }

Complexity: O(n) 

Tuesday, January 10, 2023

[LeetCode] Throne Inheritance

Problem: A kingdom consists of a king, his children, his grandchildren, and so on. Every once in a while, someone in the family dies or a child is born.

The kingdom has a well-defined order of inheritance that consists of the king as the first member. Let's define the recursive function Successor(x, curOrder), which given a person x and the inheritance order so far, returns who should be the next person after x in the order of inheritance.

Successor(x, curOrder):
    if x has no children or all of x's children are in curOrder:
        if x is the king return null
        else return Successor(x's parent, curOrder)
    else return x's oldest child who's not in curOrder

For example, assume we have a kingdom that consists of the king, his children Alice and Bob (Alice is older than Bob), and finally Alice's son Jack.

In the beginning, curOrder will be ["king"].

Calling Successor(king, curOrder) will return Alice, so we append to curOrder to get ["king", "Alice"].

Calling Successor(Alice, curOrder) will return Jack, so we append to curOrder to get ["king", "Alice", "Jack"].

Calling Successor(Jack, curOrder) will return Bob, so we append to curOrder to get ["king", "Alice", "Jack", "Bob"].

Calling Successor(Bob, curOrder) will return null. Thus the order of inheritance will be ["king", "Alice", "Jack", "Bob"].

Using the above function, we can always obtain a unique order of inheritance.

Implement the ThroneInheritance class:

  • ThroneInheritance(string kingName) Initializes an object of the ThroneInheritance class. The name of the king is given as part of the constructor.
  • void birth(string parentName, string childName) Indicates that parentName gave birth to childName.
  • void death(string name) Indicates the death of name. The death of the person doesn't affect the Successor function nor the current inheritance order. You can treat it as just marking the person as dead.
  • string[] getInheritanceOrder() Returns a list representing the current order of inheritance excluding dead people.

Example:

Input
["ThroneInheritance", "birth", "birth", "birth", "birth", "birth", "birth", "getInheritanceOrder", "death", "getInheritanceOrder"]
[["king"], ["king", "andy"], ["king", "bob"], ["king", "catherine"], ["andy", "matthew"], ["bob", "alex"], ["bob", "asha"], [null], ["bob"], [null]]
Output
[null, null, null, null, null, null, null, ["king", "andy", "matthew", "bob", "alex", "asha", "catherine"], null, ["king", "andy", "matthew", "alex", "asha", "catherine"]]

Explanation
ThroneInheritance t= new ThroneInheritance("king"); // order: king
t.birth("king", "andy"); // order: king > andy
t.birth("king", "bob"); // order: king > andy > bob
t.birth("king", "catherine"); // order: king > andy > bob > catherine
t.birth("andy", "matthew"); // order: king > andy > matthew > bob > catherine
t.birth("bob", "alex"); // order: king > andy > matthew > bob > alex > catherine
t.birth("bob", "asha"); // order: king > andy > matthew > bob > alex > asha > catherine
t.getInheritanceOrder(); // return ["king", "andy", "matthew", "bob", "alex", "asha", "catherine"]
t.death("bob"); // order: king > andy > matthew > bob > alex > asha > catherine
t.getInheritanceOrder(); // return ["king", "andy", "matthew", "alex", "asha", "catherine"]


Approach: We can make a N-ary tree and do a preorder traversal.


Implementation in C#:

public class ThroneInheritanceNode
{
    public string Name {get; private set;}
    public bool IsDead {get; private set;}
    public List<ThroneInheritanceNode> Children {get; set;}
    public ThroneInheritanceNode(string name)
    {
        this.Name = name;
        this.IsDead = false;
        this.Children = new List<ThroneInheritanceNode>();
    }
    public void MarkDead()
    {
        this.IsDead = true;
    }
}

public class ThroneInheritance
{
    public ThroneInheritance(string kingName)
    {
        this.root = new ThroneInheritanceNode(kingName);
        this.nodeMap = new Dictionary<string, ThroneInheritanceNode>();
        this.nodeMap[kingName] = root;
    }
   
    public void Birth(string parentName, string childName)
    {
        if (!nodeMap.ContainsKey(parentName))
        {
            return;
        }
        ThroneInheritanceNode node = new ThroneInheritanceNode(childName);
        this.nodeMap[childName] = node;
        this.nodeMap[parentName].Children.Add(node);
    }
   
    public void Death(string name)
    {
        if (!nodeMap.ContainsKey(name))
        {
            return;
        }
        this.nodeMap[name].MarkDead();
    }
   
    public IList<string> GetInheritanceOrder()
    {
        return this.GetInheritanceOrderDFS(this.root);
    }

    private IList<string> GetInheritanceOrderDFS(ThroneInheritanceNode node)
    {
        List<string> result = new List<string>();
        if (node == null)
        {
            return result;
        }
        if (!node.IsDead)
        {
            result.Add(node.Name);
        }
        foreach (var child in node.Children)
        {
            result.AddRange(this.GetInheritanceOrderDFS(child));
        }
        return result;
    }

    private ThroneInheritanceNode root;
    private Dictionary<string, ThroneInheritanceNode> nodeMap;
}

/**
 * Your ThroneInheritance object will be instantiated and called as such:
 * ThroneInheritance obj = new ThroneInheritance(kingName);
 * obj.Birth(parentName,childName);
 * obj.Death(name);
 * IList<string> param_3 = obj.GetInheritanceOrder();
 */

Complexity: Birth - O(1), Death - O(1), GetInheritanceOrder - O(n)