Showing posts with label Facebook. Show all posts
Showing posts with label Facebook. Show all posts

Monday, January 2, 2023

[Facebook] Replace all occurrences of 0 that are surrounded by 1 in a binary matrix

Problem: Given an M × N binary matrix, replace all occurrences of 0’s by 1’s, which are completely surrounded by 1’s from all sides (top, left, bottom, right, top-left, top-right, bottom-left, and bottom-right).

Example:

1 1 1 1
1 0 0 1
1 1 0 1
1 0 1 1

will become:

1 1 1 1
1 1 1 1
1 1 1 1
1 0 1 1


Approach: This is a similar problem to Surrounding regions where we used Flood Fill to resolve the problem. It's just here the cells are connected diagonally too. We just need to take care of it.


Implementation in C#:

    private static void ReplaceSurroundingZeroes(int[][] matrix)

    {

        int rows = matrix?.Length ?? 0;

        if (rows == 0)

        {

            return;

        }

        int cols = matrix[0].Length;

        // top boundary

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

        {

            if (matrix[0][i] == 0)

            {

                FloodFill(matrix, 0, i, 0, -1);

            }

        }

        // left boundary

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

        {

            if (matrix[i][0] == 0)

            {

                FloodFill(matrix, i, 0, 0, -1);

            }

        }

        // bottom boundary

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

        {

            if (matrix[rows - 1][i] == 0)

            {

                FloodFill(matrix, rows - 1, i, 0, -1);

            }

        }

        // right boundary

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

        {

            if (matrix[i][cols - 1] == 0)

            {

                FloodFill(matrix, i, cols - 1, 0, -1);

            }

        }

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

        {

            for (int j = 0; j < cols; ++j)

            {

                if (matrix[i][j] == 0)

                {

                    FloodFill(matrix, i, j, 0, 1);

                }

            }

        }

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

        {

            for (int j = 0; j < cols; ++j)

            {

                if (matrix[i][j] == -1)

                {

                    matrix[i][j] = 0;

                }

            }

        }

    }

    

    private static void FloodFill(int[][] matrix, int row, int col, int prevInt, int newInt)

    {

        if (!IsValidCell(matrix, row, col, prevInt))

        {

            return;

        }

        int[] dx = {-1, -1, -1, 0, 0, 1, 1, 1};

        int[] dy = {-1, 0, 1, -1, 1, -1, 0, 1};

        matrix[row][col] = newInt;

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

        {

            FloodFill(matrix, row + dx[i], col + dy[i], prevInt, newInt);

        }

    }

    

    private static bool IsValidCell(int[][] matrix, int row, int col, int target)

    {

        return row >= 0 &&

            row < matrix.Length &&

            col >= 0 &&

            col < matrix[0].Length &&

            matrix[row][col] == target;

    }


Complexity: O(m * n)


Wednesday, December 7, 2022

[LintCode][Facebook] One Edit Distance

Problem: Given two strings S and T, determine if they are both one edit distance apart.

One edit distance means doing one of these operation:

  • insert one character in any position of S
  • delete one character in S
  • change any one character in S to other character

Example:

Input: s = "aDb", t = "adb"
Output: true
Explanation: change D to d in s
Input: s = "ab", t = "ab"
Output: false
Explanation: s and t are same.


Approach: We can use the standard Edit Distance algorithm and check if the result is 1 that will definitely work. Let's try some other approach too. We need to check the following:

  1. If difference between length of s and t is more than 1 than we can safely return false.
  2. If above difference is 1 then we just need to check if removal of one character in bigger string makes both the strings same.
  3. If length of s and t are same than we just need to ensure that the number of places the characters are different in s and t is 1.

That's all!


Implementation in C#:

        public bool IsOneEditDistance(string s, string t)
{
if (s == t)
{
return false;
}

if (Math.Abs(s.Length - t.Length) > 1)
{
return false;
}

if (s.Length > t.Length)
{
return this.CanOneDeleteWork(s, t);
}

if (t.Length > s.Length)
{
return this.CanOneDeleteWork(t, s);
}

int diferences = 0;

for (int i = 0; i < s.Length; ++i)
{
if (s[i] != t[i])
{
++diferences;
if (diferences > 1)
{
return false;
}
}
}

return true;

}

private bool CanOneDeleteWork(string bigStr, string smallStr)
{
int length = smallStr.Length;

for (int i = 0; i < length; ++i)
{
if (bigStr[i] != smallStr[i])
{
return bigStr.Substring(i + 1).Equals(
                        smallStr.Substring(i));
}
}
return true;
}

Complexity: O(m * n)

Friday, October 1, 2021

[Facebook] Maximum Size Subarray Sum Equals k

Problem: Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If there isn't one, return 0 instead.

Example:

Input: nums = [1,-1,5,-2,3], k = 3
Output: 4  
Explanation: [1,-1,5,-2] is the longest subarray with sum 3.
Input: nums = [2,-1,2,1], k = 1
Output: 2
Explanation: [2,-1] or [-1,2] are the longest subarrays with sum 1.


Approach: We can use hashing here. Basically we will store the [0...i] cumulative sum as key and index i as the value. We can always check if current cumulative sum - k is in the hash table or not. If yes, we can get its index from hash table. The subarray length will be i - value_index + 1. Now we just need to get the max of such subarray's length.


Implementation in C#:

    public int maxLen(int[] arr, int n, int k)

    {

        int length = arr?.Length ?? 0;

        if (length == 0)

        {

            return 0;

        }

        var sumMap = new Dictionary<int, int>();

        int sum = 0;

        int maxLen = 0;

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

        {

            sum += arr[i];

            if (sum == k)

            {

                maxLen = i + 1;

            }

            else if (sumMap.ContainsKey(sum - k))

            {

                maxLen = Math.Max(maxLen, i - sumMap[sum - k]);

            }

            

            if (!sumMap.ContainsKey(sum))

            {

                sumMap[sum] = i;

            }

        }

        return maxLen;

    }


Complexity: O(n)

Friday, April 9, 2021

[Facebook Question][LeetCode] Verifying an Alien Dictionary

Problem: In an alien language, surprisingly they also use English lowercase letters, but possibly in a different order. The order of the alphabet is some permutation of lowercase letters.

Given a sequence of words written in the alien language, and the order of the alphabet, return true if and only if the given words are sorted lexicographically in this alien language.

Example:

Input: words = ["hello","leetcode"], order = "hlabcdefgijkmnopqrstuvwxyz"
Output: true
Explanation: As 'h' comes before 'l' in this language, then the sequence is sorted.
Input: words = ["word","world","row"], order = "worldabcefghijkmnpqstuvxyz"
Output: false
Explanation: As 'd' comes after 'l' in this language, then words[0] > words[1], hence the sequence is unsorted.
Input: words = ["apple","app"], order = "abcdefghijklmnopqrstuvwxyz"
Output: false
Explanation: The first three characters "app" match, and the second string is shorter (in size.) According to lexicographical rules "apple" > "app", because 'l' > '∅', where '∅' is defined as the blank character which is less than any other character (More info).

Constraints:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 20
  • order.length == 26
  • All characters in words[i] and order are English lowercase letters.


Approach: The approach is straight forward. We take first two words and see if they are sorted using the order string, then we check the next two words see if they are sorted. In the same way we check it for all the pairs. Here is how we can check if the pair of words say word1 and word2 are sorted or not:

  • Get the index 'i'  where word1 and word2 character where the words are different i.e. word1[i] != word2[i].
  • If word1[i]'s index is lesser than the word2[i]'s index in the order string then we can say the words are sorted otherwise not.

That's all!


Implementation in C#:

    public bool IsAlienSorted(string[] words, string order) 

    {

        int[] orderIndices = new int[order.Length];

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

        {

            orderIndices[order[i] - 'a'] = i;

        }

        for (int i = 0; i < words.Length - 1; ++i)

        {

            string word1 = words[i];

            string word2 = words[i + 1];

            if (word1.Length > word2.Length && word1.StartsWith(word2))

            {

                return false;

            }

            int j = 0;            

            while (j < word1.Length && word1[j] == word2[j])

            {

                ++j;

            }

            if (j != word1.Length)

            {

                if (orderIndices[word1[j] - 'a'] > orderIndices[word2[j] - 'a'])

                {

                    return false;

                }

            }

        }

        return true;

    }


Complexity: O(n) where n are the number of characters in all the words in input words array.

Wednesday, March 17, 2021

[Facebook Question][LeetCode] Construct Binary Tree from String

Problem: You need to construct a binary tree from a string consisting of parenthesis and integers.

The whole input represents a binary tree. It contains an integer followed by zero, one or two pairs of parenthesis. The integer represents the root's value and a pair of parenthesis contains a child binary tree with the same structure.

You always start to construct the left child node of the parent first if it exists.

Example:

Input: s = "4(2(3)(1))(6(5))"
Output: [4,2,6,3,1,5]
Input: s = "4(2(3)(1))(6(5)(7))"
Output: [4,2,6,3,1,5,7]
Input: s = "-4(2(3)(1))(6(5)(7))"
Output: [-4,2,6,3,1,5,7]


Approach: Just by looking at the examples, we can tell the input strings are kind of preorder traversal result so we are going to use preorder traversal only. 

The only thing which we need to do is we need to get the left tree ending index in advance. Here is how our algorithm will look like:

  • StrToTree(s, start, end)
    • IF (start > end)
      • RETURN null
    • leftparanthesisStartIndex = Index of '(' in s[start...end]
    • IF no '(' in s[start...end]
      • RETURN new BinaryTreeNode(int(s[start...end]) // no subtrees just return the node
    • node = new BinaryTreeNode(int(s[start...leftparanthesisStartIndex - 1])
    • leftparanthesisEndIndex = Index of ')' corresponding to '(' at leftparanthesisStartIndex in s[leftparanthesisStartIndex...end]
    • // Recursive calls
    • node.Left = CALL StrToTree(s, leftparanthesisStartIndex + 1, leftparanthesisEndIndex - 1) // No need to include '(' and ')'
    • node.Right = CALL StrToTree( leftparanthesisEndIndex + 2, end - 1) // +2 is to skip ')' and '('
    • RETURN node 

That's all!


Implementation in C#:

    public BinaryTreeNode Str2tree(string s) 

    {

        return this.Str2tree(s, 0, s.Length - 1);

    }

    

    private BinaryTreeNode Str2tree(string s, int startIndex, int endIndex)

    {

        if (startIndex > endIndex)

        {

            return null;

        }

        int leftTreeStartIndex = this.GetLeftTreeStartIndex(s, startIndex, endIndex);

        if (leftTreeStartIndex == -1)

        {

            return new BinaryTreeNode(int.Parse(s.Substring(startIndex, endIndex - startIndex + 1)));

        }

        BinaryTreeNode node = new BinaryTreeNode(int.Parse(s.Substring(startIndex, leftTreeStartIndex - startIndex)));

        int leftTreeEndIndex = this.GetLeftTreeEndIndex(s, leftTreeStartIndex, endIndex);

        // leftTreeEndIndex == -1: Should not happen

        if (leftTreeEndIndex != -1)

        {

            node.LeftNode = this.Str2tree(s, leftTreeStartIndex + 1, leftTreeEndIndex - 1);

            node.RightNode = this.Str2tree(s, leftTreeEndIndex + 2, endIndex - 1);

        }

        return node;

    }

    

    private int GetLeftTreeEndIndex(string s, int leftTreeStartIndex, int endIndex)

    {

        int leftPranthesisCount = 0;

        for (int i = leftTreeStartIndex; i <= endIndex; ++i)

        {

            if (s[i] == '(')

            {

                ++leftPranthesisCount;

            }

            else if (s[i] == ')')

            {

                --leftPranthesisCount;

            }

            // Get the corresponding ')'

            if (leftPranthesisCount == 0)

            {

                return i;

            }

        }

        return -1;

    }

    

    private int GetLeftTreeStartIndex(string s, int startIndex, int endIndex)

    {

        for (int i = startIndex; i < endIndex; ++i)

        {

            if (s[i] == '(')

            {

                return i;

            }

        }

        return -1;

    }


Complexity: O(n)

Tuesday, March 9, 2021

[Facebook Question] Missing Ranges

Problem: You are given an inclusive range [lower, upper] and a sorted unique integer array nums, where all elements are in the inclusive range.

A number x is considered missing if x is in the range [lower, upper] and x is not in nums.

Return the smallest sorted list of ranges that cover every missing number exactly. That is, no element of nums is in any of the ranges, and each missing number is in one of the ranges.

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

"a->b" if a != b

"a" if a == b

Example:

Input: nums = [0,1,3,50,75], lower = 0, upper = 99
Output: ["2","4->49","51->74","76->99"]
Explanation: The ranges are:
[2,2] --> "2"
[4,49] --> "4->49"
[51,74] --> "51->74"
[76,99] --> "76->99"
Input: nums = [], lower = 1, upper = 2
Output: ["1->2]
Explanation: The only missing range is [1,2], which becomes "1->2".


Approach: We can simply scan the whole array and add the missing ranges in the result. Please note that:

  • if nums[i] - nums[i - 1] > 1 then we know the missing range is [nums[i-1] + 1, nums[i] - 1]

We also need to take care of the conditions where lower < nums[0] and upper > nums[length - 1].

That's all!


Implementation in C#:

    public IList<string> FindMissingRanges(int[] nums, int lower, int upper) 

    {

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

        int length = nums?.Length ?? 0;

        if (length == 0)

        {

            result.Add(this.GenerateRange(lower, upper));

            return result;

        }

        if (lower < nums[0])

        {

            result.Add(this.GenerateRange(lower, nums[0] - 1));

        }

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

        {

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

            {

                result.Add(this.GenerateRange(nums[i - 1] + 1, nums[i] - 1));

            }

        } 

        if (upper > nums[length - 1])

        {

            result.Add(this.GenerateRange(nums[length - 1] + 1, upper));

        }

        return result;   

    }

    

    private string GenerateRange(int low, int high)

    {

        string range = low.ToString();

        if (high > low)

        {

            range += "->" + high;

        }

        return range;

    }


Complexity: O(n)

[Facebook Question][LeetCode] Find K Closest Elements

Problem: Given a sorted integer array arr, two integers k and x, return the k closest integers to x in the array. The result should also be sorted in ascending order.

An integer a is closer to x than an integer b if:

|a - x| < |b - x|, or

|a - x| == |b - x| and a < b

Example:

Input: arr = [1,2,3,4,5], k = 4, x = 3
Output: [1,2,3,4]
Input: arr = [1,2,3,4,5], k = 4, x = -1
Output: [1,2,3,4]


Approach: We can use queue here. We can keep enqueuing the array elements till we have count = k. Now if we have count = k and a new elements come, we enqueue it only if this element is closer than the element at the queue's front. In that case we dequeue the front element from the queue too. In the end the elements in the queue is our answer. 

The above approach works well and will solve the problem in linear time. Let's try to do little better.

We can take the advantage of the fact that the array is sorted. We can use binary search to find the index where x should be placed (x could already in the array), say the index is target_index.

Once we have the target_index, we know that the closest k elements can be the left k elements or right k elements or mix of them so we target this range [target_index - k, target_index + k - 1] and find the closest elements in it.

That's all!


Implementation in C#:

Approach 1: Using queue:

    public IList<int> FindClosestElements(int[] arr, int k, int x) 

    {

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

        int length = arr?.Length ?? 0;

        if (length == 0 || k == 0 || k > length)

        {

            return result;

        }

        // 2D array -> [0]: index [1] distance

        Queue<int[]> queue = new Queue<int[]>();

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

        {

            if (queue.Count < k)

            {

                queue.Enqueue(new int[] {i, Math.Abs(x - arr[i])});

            }

            else

            {

                if (queue.Peek()[1] > Math.Abs(x - arr[i]))

                {

                    queue.Dequeue();

                    queue.Enqueue(new int[] {i, Math.Abs(x - arr[i])});

                }

            }

        }

        while (queue.Count > 0)

        {

            result.Add(arr[queue.Dequeue()[0]]);

        }

        return result;

    }


Approach 2: Using Binary Search:

    public IList<int> FindClosestElements(int[] arr, int k, int x) 

    {    

        int length = arr?.Length ?? 0;

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

        if (length == 0 || k == 0 || k > length)

        {

            return result;

        }

        if (x < arr[0])

        {

            this.AddArrayElementsToList(arr, result, 0, k - 1);

            return result;

        }

        if (x > arr[length - 1])

        {

            this.AddArrayElementsToList(arr, result, length - k, length - 1);

            return result;

        }

        int index = Array.BinarySearch(arr, x);

        // x does not exist

        if (index < 0)

        {

            index = ~index;

        }

        int low = Math.Max(0, index - k);

        int high = Math.Min(length - 1, index + k - 1);

        while (high - low + 1 > k)

        {

            if (x - arr[low] <= arr[high] - x)

            {

                --high;

            }

            else if (x - arr[low] > arr[high] - x)

            {

                ++low;

            }

        }

        this.AddArrayElementsToList(arr, result, low, high);

        return result;

    }

    

    private void AddArrayElementsToList(int[] arr, List<int> result, int left, int right)

    {

        for (int i = left; i <= right; ++i)

        {

            result.Add(arr[i]);

        }

    }


Complexity: Approach 1: O(n), Approach 2: O(logn + k)

[Facebook Question] Strobogrammatic Number

Problem: Given a string num which represents an integer, return true if num is a strobogrammatic number

A strobogrammatic number is a number whose numeral is rotationally symmetric, so that it appears the same when rotated 180 degrees. In other words, the numeral looks the same right-side up and upside down

Example:

Input: num = "9966"
Output: true
Input: num = "1001"
Output: true


Approach: We can simply maintain a hash table say Rotation_Map with key as number and value as the number which you will get after rotating it by 180 degree. Here are the pairs -

  • 0 -> 0
  • 1 -> 1
  • 6 -> 9
  • 8 -> 8
  • 9 -> 6

Now we will reverse the given string and call it say rev_string. Now for i = 0 to length - 1 we check if num[i] exist in the rotation table and if rev_string[i] is equal to Rotation_Map[num[i]]. At any point if we see this condition is not true then we can safely return false.

In the end if we find every character in input string satisfy the condition, we return true.

 

Implementation in C#:

        public static bool IsStrobogrammatic(string num)

        {

            Dictionary<char, char> rotationMap = new Dictionary<char, char>();

            rotationMap['0'] = '0';

            rotationMap['1'] = '1';

            rotationMap['6'] = '9';

            rotationMap['8'] = '8';

            rotationMap['9'] = '6';

            char[] revArr = num.ToCharArray();

            Array.Reverse(revArr);

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

            {

                if (rotationMap.ContainsKey(num[i]) )

                {

                    if (rotationMap[num[i]] != revArr[i])

                    {

                        return false;

                    }

                }

                else if (num[i] != revArr[i])

                {

                    return false;

                }

            }

            return true;

        }


Complexity: O(n)

Sunday, March 7, 2021

[Facebook Question] Average of levels in a Binary Tree

Problem: Given a binary tree, return the average value of the nodes on each level in the form of an array.

Example:

Input:
    1
   / \
  6  10
    /  \
   11   7
Output: [1, 8, 9]
Explanation: The average value of nodes on level 0 is 1,  on level 1 is (10 + 6) / 2 = 8, and on level 2 is (11 + 7) / 2 = 9. Hence return [1, 8, 9].


Approach: A simple level order traversal / BFS can solve this question. Just look at the implementation directly to understand the approach.


Implementation in C#:

    public IList<double> AverageOfLevels() 

    {

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

        if (this.Rroot == null)

        {

            return result;

        }

        Queue<TreeNode> queue = new Queue<TreeNode>();

        queue.Enqueue(this.Root);

        while (queue.Count > 0)

        {

            int size = queue.Count;

            double sum = 0;

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

            {

                BinaryTreeNode node = queue.Dequeue();

                sum += node.Value;

                if (node.LeftNode != null)

                {

                    queue.Enqueue(node.LeftNode);

                }

                if (node.RightNode != null)

                {

                    queue.Enqueue(node.RightNode);

                }

            }

            result.Add(sum / size);

        }

        return result;

    }


Complexity: O(n)

Wednesday, March 3, 2021

[Facebook Question] Subarray Sum Equals K

Problem: Given an array of integers nums and an integer k, return the total number of continuous subarrays whose sum equals to k.

Example:

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


Approach: We can calculate cumulative sum of the array and also we can maintain a hashmap with key as sum and value as number of times key sum occurred while calculating cumulative sum.

Now the solution is just to look for cumulative sum - k in our hashmap and if it is there just add its count to the result.

That's all!


Implementation in C#:

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

        {

            Dictionary<int, int> hash = new Dictionary<int, int>();

            int count = 0, sum = 0;

            hash[0] = 1;

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

            {

                sum += nums[i];

                if (hash.ContainsKey(sum - k))

                {

                    count += hash[sum - k];

                }

                if (!hash.ContainsKey(sum))

                {

                    hash[sum] = 0;

                }

                ++hash[sum];

            }

            return count;

        }


Complexity: O(n)

Thursday, February 25, 2021

[Facebook Question][LeetCode] Backspace String Compare

Problem: Given two strings S and T, return if they are equal when both are typed into empty text editors. # means a backspace character.

Note that after backspacing an empty text, the text will continue empty.

Example:

Input: S = "ab#c", T = "ad#c"
Output: true
Explanation: Both S and T become "ac".
Input: S = "ab##", T = "c#d#"
Output: true
Explanation: Both S and T become "".
Input: S = "a##c", T = "#a#c"
Output: true
Explanation: Both S and T become "c".
Input: S = "a#c", T = "b"
Output: false
Explanation: S becomes "c" while T becomes "b".


Approach: This can be easily solved using the stack but obviously the downside is extra space. You can see the implementation. 

Let's try to reduce space. We can't traverse the string from start to end as whenever we see a backspace we need to remove the character and it will be expensive so instead of start to end, we will traverse the string from end to start. Whenever we see '#' we increase the count of backspace by 1 and if we see a character then we check if backspace count is 0 then we put the character in the result otherwise we reduce the backspace count by 1.  

That's all!


Implementation in C#:

Approach 1: Parsing string from the end to start

    public bool BackspaceCompare(string S, string T) 

    {    

        string SChas = this.GetResultString(S);

        string TChars = this.GetResultString(T);

        return SChas == TChars;

    }

    

    private string GetResultString(string str)

    {

        int bkSpCount = 0;

        StringBuilder stringBuilder = new StringBuilder();

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

        {

            if (str[i] == '#')

            {

                ++bkSpCount;

            }

            else

            {

                if (bkSpCount == 0)

                {

                    stringBuilder.Append(str[i]);

                }

                else

                {

                    --bkSpCount;

                }

            }

        }

        return stringBuilder.ToString();

    }


Approach 2: Using Stack

    public bool BackspaceCompare(string S, string T) 

    {

        char[] SChars = this.GetResultString(S);

        char[] TChars = this.GetResultString(T);

        if (SChars.Length != TChars.Length)

        {

            return false;

        }

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

        {

            if (SChars[i] != TChars[i])

            {

                return false;

            }

        }

        return true;

    }

    

    private char[] GetResultString(string str)

    {

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

        foreach (char ch in str)

        {

            if (ch == '#')

            {

                if (stack.Count > 0)

                {

                    stack.Pop();

                }

            }

            else 

            {

                stack.Push(ch);

            }

        }

        char[] result = new char[stack.Count];

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

        {

            result[i] = stack.Pop();

        }  

        return result;

    }


Complexity: O(n)

Wednesday, February 24, 2021

[Facebook Question] Add two numbers represented by strings

Problem: Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2.

Example:

Input: num1 = "99" num2 = "9"
Output: "108"


Approach: Nothing to explain here. Just look at the implementation as the approach is straight forward.


Implementation in C#:

        public string AddStrings(string num1, string num2)

        {

            char[] result = new char[Math.Max(num1.Length, num2.Length) + 1];

            int i = num1.Length - 1, j = num2.Length - 1, resultIndex = result.Length - 1, carry = 0;

            while (i >= 0 && j >= 0)

            {

                int sum = (num1[i--] - '0') + (num2[j--] - '0') + carry;

                carry = sum / 10;

                sum = sum % 10;

                result[resultIndex--] = (char)(sum + '0');

            }

            if (i >= 0)

            {

                this.SumOneNumWithCarry(result, num1, i, resultIndex, carry);

            }

            else if (j >= 0)

            {

                this.SumOneNumWithCarry(result, num2, j, resultIndex, carry);

            }

            else if (carry > 0)

            {

                result[0] = (char)(carry + '0');

            }

            return result[0] != 0 ? new string(result) : new string(result, 1, result.Length - 1);

        }


        private void SumOneNumWithCarry(char[] result, string num, int index, int resultIndex, int carry)

        {

            int resultItr = resultIndex;

            int numItr = index;

            while (numItr >= 0)

            {

                result[resultItr--] = num[numItr--];

            }

            if (carry == 1)

            {

                while (index >= 0)

                {

                    if (num[index] == '9')

                    {

                        result[resultIndex--] = '0';

                        --index;

                    }

                    else

                    {

                        ++result[resultIndex];

                        return;

                    }

                }

                result[0] = '1';

            }

        }


Complexity: O(Max(length of num1, length of num2))    

Monday, September 7, 2020

Facebook Question: Given an absolute path for a file (Unix-style), simplify it. Or in other words, convert it to the canonical path.

Problem: Given an absolute path for a file (Unix-style), simplify it. Or in other words, convert it to the canonical path.

In a UNIX-style file system, a period . refers to the current directory. Furthermore, a double period .. moves the directory up a level.

Note that the returned canonical path must always begin with a slash /, and there must be only a single slash / between two directory names. The last directory name (if it exists) must not end with a trailing /. Also, the canonical path must be the shortest string representing the absolute path.


Approach: Use stack.


        public static string SimplifyPath(string path)

        {

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

            string[] arr = path.Split('/');

            foreach(string str in arr)

            {

                if (string.IsNullOrWhiteSpace(str) || str == ".")

                {

                    continue;

                }

                else if (str == "..")

                {

                    if (stack.Count == 0)

                    {

                        continue;

                    }

                    stack.Pop();

                }

                else

                {

                    stack.Push(str);

                }

            }

            if (stack.Count == 0)

            {

                return "/";

            }

            string[] result = new string[stack.Count * 2];

            int writeIndex = result.Length - 1;

            while(stack.Count > 0)

            {

                result[writeIndex--] = stack.Pop();

                result[writeIndex--] = "/";

            }

            return string.Join("", result);

        }