Showing posts sorted by date for query Leetcode 301. Sort by relevance Show all posts
Showing posts sorted by date for query Leetcode 301. Sort by relevance Show all posts

Monday, October 5, 2020

Leetcode discuss: 301. Remove Invalid Parentheses

 Here is the link. 


C# Understand difference between return all valid strings and any valid string

Oct. 5, 2020
301. Remove Invalid Parentheses

Introduction
It was my 10:00 PM mock interview on Oct. 4, 2020. I started to prepare Google phone screen, and I have 12 free mock interviews as interviewee on interviewing dot io website. I was asked to solve the similar algorithm as hard level 301 find all valid strings, except only return one valid string. The solution can be super simple and quick to solve using less than 15 minutes.

My approach
I did come out the idea using stack to find invalid paretheses by going through once, but I did not take the hint, and then went for breadth first search and start from removing one char until a valid string is found. The solution to find only one valid string is linear time, but the following breadth first search algorithm time complexity is O((m + 1)! n), m is total number of paretheses, and n is the length of string.

After the mock interview
I quickly modified my code and then submitted as the answer of hard level 301 algorithm. The code passes all test cases. I like to write down some lessons I learned through the practice.

Highlights of discussion in mock interview of my implementation:

  1. Time complexity, if the string is 10 of open paretheses, "((((((((((", and then each index position will have to be considered to be removed, 10 substrings will be added to queue, next round each string has length of 9, 9 subsring will be added to queue for each of them, so total is 10 * 9, therefore, the total of string is 10!. The interviewer corrected my estimation of time complexity: not O(m * n), should be O((m + 1)! * n), whereas m is total number of paretheses, n is length of string.
  2. Duplicate removal - inside while loop, the second for loop start index should be bigger than previous one - parent string. More detail not "j = 0", should be "j = item2" saved from Queue.
  3. Inside while loop, the second for loop, the string to enqueue should start from j, not j + 1, since j position's char is removed.

My performance on mock interview
I did some analysis based on a few simple test cases first, and then I told the interviewer that I like to write code to make sure those few simple test cases working at least.

// bfs -> VALID BRUTE FORCE
// ONCE - SHOULD BE Minimum number
// BFS ->
// ()() -> ok
// (() -> remove one, index 0 or 1 -> find valid (), remove open
// ()(( -> remove two,
// check not valid
// 0 )(( -> queue
// 1 (((
// 2 ()(
// 3 ()( -> queue
// ------------------------
// 0 )(( -> queue
// 1 (((
// 2 () -> valid string found!
// 3 ()( ->
()()))
--
)()))


Feedback I like to look into

It takes me long time to master this hard level algorithm: 301. Remove Invalid Parentheses. Without practice and help from interviewers, it will take me more time to understand my weakness. I like to work on my communication skills as well besides coding and analysis, requirement gathering.

Here are some feedbacks I like to think about after the mock interview:
Help your interviewee get better!

  1. The interviewee proposed a stack solution, which is in the right direction of the optimal solution, but she then dropped it and proposed a BFS solution. The BFS solution is sub-optimal as it would take more space.
  2. Once the interviewer explicitly mentioned the proposed solution makes sense and can go ahead with implementation, it would be better for the interviewee to jump into the implementation instead of spending extra time on explaining the idea more.
  3. During implementaion, the interviewee considered the edge cases, such as empty input and 0-length string.
  4. The actual implementation is sub-optimal in terms of time complexit.
  5. The code can be cleaner. The inconsistent indentation hurts the readability of the code.
  6. The interviewee proactively thought of more efficient optimization based on the original solution, though the improvement introduced bugs.
  7. The time and space complexity based on the implementation should be at the scale of factorial instead of polynomial.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _301_all_valid_paratheses
{
    class Program
    {
        static void Main(string[] args)
        {
            var list = RemoveInvalidParentheses("(a)(b(a)"); 
        }

        /// <summary>
        /// Oct. 5, 2020
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static IList<string> RemoveInvalidParentheses(string s)
        {
            if (s == null || s.Length == 0)
            {
                new string[] { "" }.ToList();
            }
    
            if(isValid(s))
            {               
                return new String[]{s}.ToList() ; 
            }

            var set = new HashSet<string>(); 
            // queue - BFS - save index position of open or close parentheses
            // index - int[], size - 2, index position - second - 0, close 1
            // Tuple<string, int>
            var queue = new Queue<Tuple<string, int>>(); 
            queue.Enqueue(new Tuple<string,int>(s, 0)); 
            
            // (a)b)
            // ()((
            //  - 
            // ((((((( -> 
            // O(m * m * N * N) - 
            // m is how many strings (count of parenthese), n is size of string - 4
            // space -> queue O(m! * n) - m is count of parent chars in string 
            // m + m*(m-1) + m(m-1)(m-2) + ... + m!
            // m* m!= (m+1)! loosely upper bound
            // 10 -> 10*9 -> 10*9*8 
            // 10 -> 10: 9 -> 90: 8
            while(queue.Count > 0)
            {
                // BFS  - every string will be check - O(m) count of parenthese < N
                var count = queue.Count; 
        
                for(int i = 0; i < count; i++)
                {
                    //(a)b)
                    var current = queue.Dequeue(); 
                    var item1 = current.Item1;
                    var item2 = current.Item2;
            
                    //  O(N * N)
                    for(int j = item2; j < item1.Length; j++) // (
                    {
                        var c = item1[j];
                        var isPare = c == '(' || c== ')';
                
                        if(isPare)
                        {
                            var tmp = item1.Substring(0, j) + item1.Substring(j + 1, item1.Length - j - 1);
                            if(isValid(tmp))
                           {
                               set.Add(tmp);                               
                           }
                           else 
                           {  // one char shorter 
                              queue.Enqueue(new Tuple<string, int>(tmp, j)); 
                           }
                       }                       
                    }            
                }

                if (set.Count > 0)
                {
                    break;
                }                                  
            }

            return set.ToList(); 
        }

        // O(N) - N length of S                       
        private static bool isValid(string s)
        {
          if(s == null || s.Length == 0)
            return true;
                           
          int openCount = 0;                           
                           
          for(int i = 0; i < s.Length; i++)
          {
             var c = s[i];
             if(c == '(')
             {
              openCount++;
             }
             else if(c == ')')
             {
                if(openCount == 0)
                {
                  return false;
                }
                                   
                openCount--; 
             }
          }
                           
          return openCount == 0; 
        }
    }
}


Tuesday, June 23, 2020

Leetcode discuss: 301 remove invalid parentheses

Here is the link.

C# BFS approach without pruning practice in June 2020

June 23, 2020
301 remove minimum invalid parentheses
Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.
How to study a solution written in BFS?
I did learn the idea back in 2018. After two years, I learned and value the case study method.
It is important for me to write down a few simple test cases first, and then go over one by one to explain to myself first, how to apply BFS and make it work.
Case study approach from Harvard business school teaching is my favorite learning technique now.
I like to study the BFS solution again written in Java. The link is here.
2020 June 23 - review BFS solution
I plan to write a C# solution using the same idea. I will write a case study to explain how to approach the problem.
I spent a few hours to write a solution on June 22, 2020, here is the link.
I debugged the code using string "())" step by step, it is hard for me to understand the design. So I decide to remove pruning part, focus on basic BFS algorithm. Keep minimum to solve the problem first using BFS.
I decided to continue to remove those code hard to understand, in other words, make it work for Leetcode online judge, remove those pruning ideas first.
Case study
I think that it is important to go over test cases and then talk about how to solve the problem. The following is to go over valid string, remove one parenthese, two parentheses three test cases.
Case study 1: "()", or any valid string
The string is valid, so first step in my design is to check original string is valid or not.
If it is, then return original string. Othewise at least one parenthese should be removed.
Case study 2: Remove one parentheses
For example "())", minimum number of invalid parentheses is 1, result is "()".
"(()"
How to design using BFS algorithm, using Queue to help.
Remove one char from index = 0 to last one, and see if the substring is valid or not.
index = 0, "))", not valid
index = 1, "()", valid
index = 2, "()", valid
The way to skip the duplicate valid string is to save in the hashset first, and then convert set to List object.
Rule 1:
Always consider to put "))" in the queue to process since original one "())" is not a valid string.
One more test to remove one char - case study 2
")()"
First, it is not valid parentheses string. So at least one parenthese should be removed.
Go over each index position of string ")()", remove the char,
First one is index = 0; "()" is valid one, so "()" is added to output;
Second one is index = 1; "))" is not valid, but output list is not empty, continue;
Third one is index = 2; ")(" is not valid one.
It is important to go over a few simple test cases to understand how BFS works, and then it is time to think about how to prune the algorithm and make it more efficient.
Here are those two important steps:
First, push Tuple<string, int>("())",0) into queue;
and then go over each index position from "())", remove each char, see if it is valid or not.
Case study 3: Remove two parentheses
String "())(()", how to find the valid string "()()" to remove two parentheses?
The above test case is so helpful for me to understand BFS, first remove one parenthese, all those substrings are not valid string, which should be queued for next removal of one more parenthese.
Work on the iteration. I will add more explanation for this test case.
"))(()", 0
"()(()", 1
"()(()", 2
"())()", 3
"())()", 4
"())((", 5
From the above four test cases, "())()", 4 should be same as "())()", 3. So it is not needed to be repeated.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _301_remove_invalid_parentheses___2020
{
    class Program
    {
        static void Main(string[] args)
        {
            //var reuslt  = RemoveInvalidParentheses("()"); // original one valid or not - step 1
            //var result2 = RemoveInvalidParentheses("())"); // need to remove one parentheses - step 2
            var result3 = RemoveInvalidParentheses("())(()");
        }

        /// <summary>
        /// code review on June 22, 2020
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static IList<string> RemoveInvalidParentheses(string s)
        {
            var set = new HashSet<string>(); 

            // return if it is valid
            if (IsValidParentheses(s))
            {
                set.Add(s);
                return set.ToList();
            }

            // How to design a queue - BFS to solve the problem? 
            // think about a string to remove two parentheses, "())(()", 
            // those strings with one char removed should be enqueued for next removal of char
            var queue = new Queue<Tuple<string, int>>();

            //The 2-Tuple is (string, startIndex)                        
            queue.Enqueue(new Tuple<string, int>(s, 0));            

            while (queue.Count > 0)
            {
                var current = queue.Dequeue();

                var search = current.Item1;
                var start = current.Item2;               

                // Start from last removal position 
                for (int index = start; index < search.Length; ++index)
                {
                    var visit = search[index];

                    //Not parentheses
                    bool isParenthese = visit == '(' || visit == ')';
                    if (!isParenthese)
                    {
                        continue;
                    }                                        

                    // remove visit char from the string
                    //var skipCurrent = search.Substring(0, index) + search.Substring(index + 1);
     var skipCurrent = search.Remove(index, 1);
     
                    //Check the string is valid
                    if (IsValidParentheses(skipCurrent))
                    {
                        set.Add(skipCurrent);
                        continue; // continue to iterate all index positions 
                    }

                    // think about test case: ())(() -> minimum is to remove two parentheses
                    // Strings with one char removed are not working, then BFS goes to second remove
                    // Four strings will be in the queue. 
                    // "))(()", 0
                    // "()(()", 1
                    // "()(()", 2
                    // "())()", 3
                    // "())()", 4 
                    // "())((", 5    
                    if (set.Count == 0)
                    {
                        queue.Enqueue(new Tuple<string, int>(skipCurrent, index));
                    }
                }
            }

            return set.ToList();
        }

        /// <summary>
        /// test case: 
        /// "()","(())", "()()"  true
        /// ")(","())"  false
        /// Time complexity: O(N)
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool IsValidParentheses(String s)
        {
            int count = 0;
            for (int i = 0; i < s.Length; ++i)
            {
                var visit = s[i];
                var isOpen = visit == '(';
                var isClose = visit == ')';

                if (isOpen)
                {
                    ++count;
                }

                if (isClose)
                {
                    bool noOpenToMatch = count <= 0;

                    if (noOpenToMatch)
                    {
                        return false;
                    }

                    count--;
                }
            }

            return count == 0;
        }
    }
}


Monday, June 22, 2020

LeetCode 301. Remove Invalid Parentheses - DFS case study by Huahualeetcode

Here is the link.



Here is the code example in C++.

I spent 25 minutes to watch the video. The explanation is very clear and very straightforward to apply BFS, no pruning. I do like to work on the solution first using DFS, make it work, and then think about more if I have time to add some pruning ideas. 



C++ code is also saved in a gist. Here is the gist.



I will write a C# solution using the same idea. 

Sunday, June 23, 2019

Leetcode - Facebook

Facebook (111)
534 Design TinyURL
283 Move Zeroes
301 Remove Invalid Parentheses
273 Integer to English Words
325 Maximum Size Subarray Sum Equals k
67 Add Binary
621 Task Scheduler
253 Meeting Rooms II
17 Letter Combinations of a Phone Number
311 Sparse Matrix Multiplication
91 Decode Ways 19.8%
297 Serialize and Deserialize Binary Tree
314 Binary Tree Vertical Order Traversal
10 Regular Expression Matching
15 3Sum
158 Read N Characters Given Read4 II – Call multiple times
278 First Bad Version
277 Find the Celebrity
200 Number of Islands
76 Minimum Window Substring
257 Binary Tree Paths
282 Expression Add Operators
23 Merge k Sorted Lists
157 Read N Characters Given Read4
121 Best Time to Buy and Sell Stock
602 Friend Requests II: Who Has the Most Friends
56 Merge Intervals
161 One Edit Distance
173 Binary Search Tree Iterator
1 Two Sum
543 Diameter of Binary Tree
211 Add and Search Word – Data structure design
341 Flatten Nested List Iterator
252 Meeting Rooms
125 Valid Palindrome
597 Friend Requests I: Overall Acceptance Rate
139 Word Break
636 Exclusive Time of Functions
285 Inorder Successor in BST
78 Subsets
98 Validate Binary Search Tree
43 Multiply Strings
75 Sort Colors
670 Maximum Swap
57 Insert Interval
133 Clone Graph
215 Kth Largest Element in an Array
33 Search in Rotated Sorted Array
13 Roman to Integer
206 Reverse Linked List
79 Word Search
494 Target Sum
236 Lowest Common Ancestor of a Binary Tree
398 Random Pick Index
477 Total Hamming Distance
38 Count and Say
680 Valid Palindrome II
49 Group Anagrams
88 Merge Sorted Array
218 The Skyline Problem
146 LRU Cache
238 Product of Array Except Self
209 Minimum Size Subarray Sum
102 Binary Tree Level Order Traversal
90 Subsets II
71 Simplify Path
286 Walls and Gates
128 Longest Consecutive Sequence
639 Decode Ways II
523 Continuous Subarray Sum
334 Increasing Triplet Subsequence
208 Implement Trie (Prefix Tree)
28 Implement strStr()
269 Alien Dictionary
127 Word Ladder
647 Palindromic Substrings
377 Combination Sum IV
20 Valid Parentheses
44 Wildcard Matching
554 Brick Wall
235 Lowest Common Ancestor of a Binary Search Tree
380 Insert Delete GetRandom O(1)
50 Pow(x, n)
117 Populating Next Right Pointers in Each Node II
69 Sqrt(x)
461 Hamming Distance
85 Maximal Rectangle
210 Course Schedule II
26 Remove Duplicates from Sorted Array
68 Text Justification
221 Maximal Square
274 H-Index
404 Sum of Left Leaves
25 Reverse Nodes in k-Group
234 Palindrome Linked List
689 Maximum Sum of 3 Non-Overlapping Subarrays
80 Remove Duplicates from Sorted Array II
168 Excel Sheet Column Title
261 Graph Valid Tree
265 Paint House II
275 H-Index II
410 Split Array Largest Sum
525 Contiguous Array
674 Longest Continuous Increasing Subsequence
572 Subtree of Another Tree
578 Get Highest Answer Rate Question
637 Average of Levels in Binary Tree
642 Design Search Autocomplete System
653 Two Sum IV – Input is a BST
673 Number of Longest Increasing Subsequence
535 Encode and Decode TinyURL