Thursday, September 3, 2020

Given a linked list, remove the n-th node from the end of list.

Note: Condition was given that n will always be valid.

Approach: Use two pointers.

Implementation in C#:

        public void RemoveNthFromEnd(int n)

        {

            LinkedListNode first = this.Head, second = this.Head;

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

            {

                second = second.Next;

                if (second == null)

                {

                    this.Head = this.Head.Next;

                    return;

                }

            }

            while (second.Next != null)

            {

                first = first.Next;

                second = second.Next;

            }

            first.Next = first.Next.Next;

        }

Complexity: O(n)

Wednesday, September 2, 2020

[Uber][LeetCode] Regular Expression Matching

Problem: Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*' where:

  • '.' Matches any single character.​​​​
  • '*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

Example:

Input: s = "aa", p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Input: s = "aa", p = "a*"
Output: true
Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Input: s = "ab", p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".


Approach: Use DP. Have a table [s.Length + 1][p.Length + 1] where table[i][j] indicates s(0..i-1) is a match of pattern p(0...j-1). Once we fill this we need to return table[s.Length][p.Length]. Here is how to fill this table - 

  1. If pattern and string both are null then its a match so table[0][0] is always true.
  2. If pattern is null (p.Length = 0) then its a mismatch so table[i][0] = false for i = 1...s.Length.
  3. If string is null then table[0][j] can be true only if pattern has p[j - 1] = '*' and table[0, j - 2] is true for j = 1...p.Length
  4. table[i][j] = table[i-1][j-1] if current pattern character i.e. p[j - 1] is either . or match with current char of string i.e. s[i-1]
  5. If p[j - 1]  is '*' then
    1.   a. if previous char in pattern match current char of s i.e. p[j - 2] is '.' or s[i-1] then table[i][j] = table[i][j-2] || table[i-1][j]
    2. if not then table[i][j] = table[i][j-2]
  6. table[i][j] = false.


Implementation in C#:

        public bool IsRegexMatch(string s, string p)

        {

            bool[,] lookup = new bool[s.Length + 1, p.Length + 1];

            lookup[0, 0] = true;

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

            {

                if (p[i - 1] == '*')

                {

                    lookup[0, i] = i - 2 >= 0 ? lookup[0, i - 2] :false;

                }

            }

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

            {

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

                {

                    if (p[j - 1] == '*')

                    {

                        lookup[i, j] = lookup[i, j - 2];

                        if (p[j - 2] == '.' || p[j - 2] == s[i - 1])

                        {

                            lookup[i, j] = lookup[i, j - 2] || lookup[i - 1, j];

                        }

                    }

                    else if (p[j - 1] == '.' || s[i - 1] == p[j - 1])

                    {

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

                    }

                    else

                    {

                        lookup[i, j] = false;

                    }

                }

            }

            return lookup[s.Length, p.Length];

        }


Complexity: O(m * n)

Longest Palindromic Substring

Approach: The idea is to generate all even length and odd length palindromes and keep track of the longest palindrome seen so far.

To generate odd length palindrome, Fix a centre and expand in both directions for longer palindromes, i.e. fix i (index) as center and two indices as i1 = i+1 and i2 = i-1

Compare i1 and i2 if equal then decrease i2 and increase i1 and find the maximum length.

Use a similar technique to find the even length palindrome.

Take two indices i1 = i and i2 = i-1 and compare characters at i1 and i2 and find the maximum length till all pair of compared characters are equal and store the maximum length.


        public string LongestPalindromicSubString(string str)

        {

            if(string.IsNullOrEmpty(str))

            {

                return string.Empty;

            }

            int maxLength = 1;

            int start = 0;

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

            {

                // Find the longest even length palindrome with center points as i-1 and i.

                int low = i - 1;

                int high = i;

                while(low >= 0 && high < str.Length && str[low] == str[high])

                {

                    if (high - low + 1 > maxLength)

                    {

                        start = low;

                        maxLength = high - low + 1;

                    }

                    --low;

                    ++high;

                }

                // Find the longest odd length palindrome with center point as i

                low = i - 1;

                high = i + 1;

                while(low >= 0 && high <str.Length && str[low] == str[high])

                {

                    if (high - low + 1 > maxLength)

                    {

                        start = low;

                        maxLength = high - low + 1;

                    }

                    --low;

                    ++high;

                }

            }

            return str.Substring(start, maxLength);

        }


Complexity: O(n^2)

[LeetCode] Longest Substring Without Repeating Characters

Problem: Given a string s, find the length of the longest substring without repeating characters.

Example:

Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.


Approach: Clearly it's a sliding window problem. Like in any other sliding window problem we will maintain start and end indices of current window. We can have a hash map but we can use hash set here as the occurrence of  every character in substring can't be more than one. We will keep incrementing end by 1 and for each index 'end', there could be 2 cases:

  1. s[end] is not in current window means it won't be in our hash set too. We can simply add s[end] to hash set i.e. add s[end] to current window. We will also see if the current window length is more than max length then we can assign current length to max length.
  2. s[end] is already in current window means it is already in our hash set. In this case we need to slide our window from the left. Means we will keep increasing start index of window and keep removing s[start] from hash set until s[end] character is removed from the hash set / current window.
In the end we will just return the max length. That's all!


Implementation in C#:

    public int LengthOfLongestSubstring(string s)
    {
        int length = s?.Length ?? 0;
        if (length <= 1)
        {
            return length;
        }
        HashSet<char> charSet = new HashSet<char>();
        int start = 0;
        int end = 0;
        int maxLen = 0;
        for ( ; end < length; ++end)
        {
            if (charSet.Contains(s[end]))
            {
                maxLen = Math.Max(maxLen, end - start);
                while (charSet.Contains(s[end]))
                {
                    charSet.Remove(s[start++]);
                }
            }
            charSet.Add(s[end]);
        }
        return Math.Max(maxLen, end - start);
    }


Complexity: O(n)

Median of 2 sorted arrays

Example: Input : ar1[] = {-5, 3, 6, 12, 15}

        ar2[] = {-12, -10, -6, -3, 4, 10}

        The merged array is :

        ar3[] = {-12, -10, -6, -5 , -3,

                 3, 4, 6, 10, 12, 15}

Output : The median is 3.

Solution: Start partitioning the two arrays into two groups of halves. The first half contains some first elements from the first and the second arrays, and the second half contains the rest elements form both arrays. Reach a condition such that, every element in the first half is less than or equal to every element in the second half.

    public double FindMedianSortedArrays(int[] nums1, int[] nums2)

    {

            if (nums1 == null && nums2 == null)

            {

                return -1;

            }

            if (nums1.Length == 0 && nums2.Length == 0)

            {

                return -1;

            }

            if (nums1.Length <= nums2.Length)

            {

                return this.FindMedianSortedArraysInternal(nums1, nums2);

            }

            else

            {

                return this.FindMedianSortedArraysInternal(nums2, nums1);

            }

        }

        private double FindMedianSortedArraysInternal(int[] nums1, int[] nums2)

        {

            int minIndex = 0, maxIndex = nums1.Length, nums1Index = 0, nums2Index = 0;

            double median = 0;

            while (minIndex <= maxIndex)

            {

                nums1Index = (minIndex + maxIndex) / 2;

                nums2Index = ((nums1.Length + nums2.Length + 1) / 2) - nums1Index;

                if (nums2Index < 0)

                {

                    maxIndex = nums1Index - 1;

                    continue;

                }

                // if num1Index = num1.Length, it means that elements from num1 in the second half is an  

                // empty set. and if num2Index = 0, it means that elements from num2 in the first half is an

                // empty set. so it is necessary to check that, because we compare elements from these two

               // groups. Searching on right  

                if (nums1Index < nums1.Length && nums2Index > 0 && nums2[nums2Index - 1] > nums1[nums1Index])

                {

                    minIndex = nums1Index + 1;

                }

                // if num1Index = 0, it means that Elements from num1 in the first half is an empty set and if 

                // num2Index = num2.Length, it means that Elements from num2 in the second half is an 

                // empty set. so it is necessary to check that, because we compare elements from these two

                // groups. searching on left

                else if (nums1Index > 0 && nums2Index < nums2.Length && nums2[nums2Index] < nums1[nums1Index - 1])

                {

                    maxIndex = nums1Index - 1; 

                }

                // Found the desired halves

                else

                {

                    // this condition happens when we don't have any elements in the first half from num1 so

                    // we returning the last element in num2 from the first half.

                    if (nums1Index == 0)

                    {

                        median = nums2[nums2Index - 1];

                    }

                    // this condition happens when we don't have any elements in the first half from num2 so

                    // we returning the last element in num1 from the first half.

                    else if (nums2Index == 0)

                    {

                        median = nums1[nums1Index - 1];

                    }

                    else

                    {

                        median = Math.Max(nums1[nums1Index - 1], nums2[nums2Index - 1]);

                    }

                    break;

                }

            }

            // If number of elements is odd there is one middle element. 

            if ((nums1.Length + nums2.Length) % 2 == 1)

            {

                return median;

            }

            // Elements from nums1 in the second half is an empty set.

            if (nums1Index == nums1.Length)

            {

                return (median + nums2[nums2Index]) / 2;

            }

            // Elements from nums2 in the second half is an empty set.

            if (nums2Index == nums2.Length)

            {

                return (median + nums1[nums1Index]) / 2;

            }

            return (median + Math.Min(nums1[nums1Index], nums2[nums2Index])) / 2;      

        }

Thursday, September 10, 2015

Next Greater Element

Problem Statement:-
Given an array, print the Next Greater Element (NGE) for every element. The Next greater Element for an element x is the first greater element on the right side of x in array. Elements for which no greater element exist, consider next greater element as -1.
For the input array [4, 5, 2, 25}, the next greater elements for each element are as follows.
Element       NGE
   4      -->   5
   5      -->   25
   2      -->   25
   25     -->   -1

Solution in JAVA int time complexity O(n) 
import java.io.*;
import java.util.*;
class nextGreater
{
    public static void nextGreat( int a[], int len)
    {
        int element, next;
        Stack mystack = new Stack();
        for(int i=0; i<len; i++)
        {   
            next = a[i];
            while(!mystack.empty())
            {
                element=(int)mystack.pop();
                if(element > next)
                {
                    //push back the element 
                    mystack.push(element);
                    break;
                }
                else
                {
                    System.out.println( element +"-------->"+next);
                }
            }
            mystack.push(a[i]);
        }
        while(!mystack.empty())
        {
            element = (int)mystack.pop();
            System.out.println( element +"-------->"+"-1");
        }
        return;
    }
    public static void main(String []args)
    {
        int a[] = {1,2,23,3,4,205,25,1,2,100,2,3,4,200,105};
        nextGreat(a,a.length);
     }
}

Thursday, September 3, 2015

Minimum Initial Points to Reach Destination


Given a grid with each cell consisting of positive, negative or no points i.e, zero points. We can move across a cell only if we have positive points ( > 0 ). Whenever we pass through a cell, points in that cell are added to our overall points. We need to find minimum initial points to reach cell (m-1, n-1) from (0, 0).


Constraints :
  • From a cell (i, j) we can move to (i+1, j) or (i, j+1).
  • We cannot move from (i, j) if your overall points at (i, j) is <= 0.
  • We have to reach at (n-1, m-1) with minimum positive points i.e., > 0
Example

Input: points[m][n] = { {-2, -3,   3}, 
                        {-5, -10,  1}, 
                        {10,  30, -5} 
                      };
Output: 7
Explanation: 
7 is the minimum value to reach destination with 
positive throughout the path. Below is the path.

(0,0) -> (0,1) -> (0,2) -> (1, 2) -> (2, 2)

We start from (0, 0) with 7, we reach(0, 1) 
with 5, (0, 2) with 2, (1, 2) with 5, (2, 2)
with and finally we have 1 point (we needed 
greater than 0 points at the end). 

pasting the code below, please let me know if you found any bug in it.
import java.io.*;

class minInitialDP
{
    public static int max(int x, int y)
    {
        return (x>y?x:y);
    }

    public static int min(int x, int y)
    {
        return (x<y?x:y);
    }

    public static void main(String []args)
    {
        int points[][] = { {-2, -3,   3}, 
                        {-5, -10,  1}, 
                        {10,  30, -5} 
                      };

        int DP [][] = new int[3][3];

        // main code goes here 

        for(int i=0; i<3; i++)
        {
            for(int j=0; j<3; j++)
            {
                if (i==0 && j==0)
                {
                    DP[i][j] = 0;
                    continue;
                }

                if( i==0 )
                {
                    if(points[i][j-1] < 0)
                    {
                        DP[i][j] = -points[i][j-1]+DP[i][j-1]+1;       
                    }
                    else
                    {
                        DP[i][j] = DP[i][j-1];
                    }
                    continue;
                }

                if(j==0)
                {
                    if(points[i-1][j] < 0)
                        DP[i][j] = -points[i-1][j]+DP[i-1][j]+1;
                    else
                        DP[i][j] = DP[i-1][j];
                    continue;
                }

                int pi, pj;

                if(points[i][j-1] < 0)
                    pi = -points[i][j-1]+DP[i][j-1]+1;
                else
                    pi =  DP[i][j-1];

                if(points[i-1][j] < 0)
                    pj = -points[i-1][j]+DP[i-1][j]+1;
                else
                    pj = DP[i-1][j];

                DP[i][j] = min(pi, pj);
            }
        }

        for(int i=0; i<3; i++)
        {
            for(int j =0; j<3; j++)
                 System.out.print(DP[i][j] + " ");
            System.out.println("\n");
        }
    }

}