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

Tuesday, July 24, 2018

One week for new habit

Introduction


I like to write down if I can build a new habit to code every day, using leetcode online judge to train myself.


How many days does it take for me to build a habit to write code daily?

I find out that it is easy to write code for easy level algorithms on Leetcode.com. I like to write easy level algorithms to train myself in next two weeks. Also I like to do some small research how to build a good habit to write code daily.

One week 24 algorithms


I wrote three hard, two medium, 19 easy level algorithms in one week. I train myself in a week using those 23 algorithms.

I started from July 17 to July 24, I wrote 23 algorithms and also passed Leetcode online judge. The algorithms are

Easy level
63, 88
113, 198,
202, 203, 205, 231, 234, 277, 278, 283, 290
303, 326, 343, 349, 387,
438,

Medium level
556
648

Hard level

132
273
301

In order to pass Leetcode online judge for the above 23 algorithms, I did a lot of work and surprisingly I was so happy to write code for those algorithms. I am a happy problem solver.

Leetcode 301 Remove invalid parentheses


It is hard level algorithm. I worked on the algorithm more than 12 months ago I have to make algorithm simple as remembering one test case, how to come out the story how to solve it, for example, hard level algorithm 301. Here is my practice documented in the blog.

Leetcode 648 redudant connection



Also I learn that I spent time to write down my frustration and learning more than 6 months ago, but at that time I did not learn that it is most important to write the code for the algorithm and pass online judge.

To build a new habit to write code and run against Leetcode online judge.

Tuesday, February 20, 2018

Train insane or remain the same

Feb. 20, 2018

Introduction


I always like to answer people why I continuously practice mock interview. I believe that I treat it like a research project. I like to find out what I can learn quickly through those practice.

I love to meet people and then have discussion related to the algorithm and data structure. I just treat the mock interview as one of my research projects, things I can work hard and then see if I can make a difference on myself or the peer. Learning and teaching are most interesting things I like to do.

I love to teach algorithm and data structure, I go through those long hours to work with peers on algorithm problem solving. From those experience, I educate myself to be super patient when I meet an algorithm and I need to break through in less than 20 minutes.


My two mock interviews


One thing I did last weekend is to go through the mock interviews from a startup company, and so surprisingly I passed two round of mock interviews, first one is average 2.7, second one is average 2.5.

Life is such a great teacher. One of my friends told me that he did first one 3.2 but second one did not pass passing bar 2.5, which is below 2.0.

So I suddenly find out that I should think about it. Do not take it for granted. At least I should write down and then later on I can tell something from this experience.


Leetcode 301 Algorithm practice


I like to figure out how to improve my practice. Just before the mock interview to work on remove invalid parentheses, I worked on leetcode 301 hard level algorithm continuously from February 3 to February 7 2018, and my goal was to practice over 10 times and also tried various ideas. Here is the list of practice by searching the blog using Leetcode 301.

One thing I like to look into is that I could not recall the tip to remove invalid parentheses. The most simple way to remove invalid parentheses is to remove unmatched close bracket first, and then reverse the string, and then handle the same subproblem.

What I can tell is that the practice does not help right away for the mock interview. I got the average score 2.5, but score of coding is 2.3. I did know that I just practiced the algorithm and got my hands on those ideas one by one, but I could not quickly enough to apply related work to the problem solving right away. The interviewer gave me 5 minutes talk after mock interview, he told me that the first algorithm took me around 30 minutes which should less than 20 - 25 minutes.

What if I did not review the algorithm, and went over all the practices I did over 6 hours.


Saturday, February 17, 2018

Remove invalid parentheses

Feb. 17, 2018

Introduction


It is my most favorite algorithm to work on recently. I started to work on Leetcode 301 - remove invalid parentheses, a hard level algorithm

Time line


Step 1:

I had 9:30 AM mock interview, and the algorithm I had to work on is to find minimum valid parentheses. Based on the interviewer's advise, I had to work on step 1, remove invalid parentheses.

It should take me at most 20 to 25 minutes to finish the algorithm and also coding, but I actually spent over 35 minutes but the code has bugs.

Here is the code in mock interview

Step 2:

Started from 1 PM, I worked on the code I wrote in mock interview, completed the code, and the code has bug. Here is the code.

Step 3:

2:47 pm, I rewrote the code using different design, and complete the test cases. The code is here for remove invalid parentheses.

Step 4:

Not it is 2:55 PM, I organized all the past practice Leetcode 301, added tag for each post using tag: Leetcode 301: remove invalid parentheses. All the past practice can be looked up by the tag now.


Actionable Items


March 5, 2018 8:10 PM
It has been more than three weeks, I think about carefully what really the problem is for this algorithm problem solving.

I need to simplify the problem I need to solve.

Saturday, February 3, 2018

Leetcode 301: Remove invalid parentheses (I)

Feb. 3, 2017

Introduction


I like to work on a hard level algorithm on leetcode.com. Also I do not like to rush and find the answer as I do sometimes. Through the learning experience of Leetcode 10: regular expression matching, I know that it may take me 10 practice before I can fully understand the hard level algorithm.


First 30 minutes


On Feb. 6, 2018 I had chance to work on the algorithm called Leetcode 301: removed invalid parentheses. I like to write down the notes and see if I can find the answer through the first 30 minutes work.





Thursday, February 8, 2018

Leetcode 54: Spiral matrix - think recursively

Feb. 8, 2018

Introduction


It is my idea how to train myself in the practice. It is to involve the discussion of Leetcode. Every algorithm I should give out 10 votes for 10 different ideas, and also write C# code based on the idea.

I did some research based on my practice of Leetcode 301 recently, and I found out that my practice has some issue. And I wrote a blog how to learn a hard level algorithm on Leetcode.com.


Recursive solution


I studied the solution today, and I like to write a C# code based on the idea. It is the great warm up of recursive function, and also nice to review base cases in the design of recursive function. Here is the C# code.



Wednesday, February 7, 2018

How to learn a hard level algorithm on Leetcode?

Feb. 7, 2018

Introduction


I chose to work on Leetcode 301: remove invalid parentheses, and then I spent 30 minutes to work on the algorithm last Saturday Feb. 3, 2018. And this past Tuesday night I browsed all the blogs and then I found that I worked on the algorithm last July 2017. So I was so surprised and then I had to look into what is going on. How come I do not have any clue that I work on the algorithm over hours.

I was so surprised to read my own blog and then just amazed that how time can take away everything. Hard work and long journey of coding, design and study. Here is the blog dated on July 2017. I even wrote an answer in discussion and then got 3 reputation. I did not aware that I had positive reputation, last time I checked I only have zero reputation.

How to learn a hard level algorithm? 


It is important to practice again and again on the same hard level algorithm. My last practice in July 2016 seems not working very well, because I could not remember too much detail about how to write recursive function, tips and tricks.

This time I changed the plan. I like to focus on more on ideas. I tried to write more than five blogs for each idea of the algorithm, and write down my own notes for each idea. Hopefully I can learn more things from one hard level algorithm.

There are so many algorithms, I can not work on a lot of them. Just get familiar with hard level one.

What I like to do is to leave 10 discussions comment for other people's post in leetcode discussion panel, and also vote up to 10 ideas to encourage people sharing. Get involved more about sharing ideas on the hard level algorithm. Do not be biased on ideas.



Leetcode 301: remove invalid parentheses (V)

Feb. 7, 2018

It is such a good workout that I wrote a C# code based on one of solutions in Leetcode discussion. Here is my C# solution.


Friday, July 13, 2018

infix expression to construct binary expression tree

July 13, 2018

Introduction


It is my favorite thing to do to scan the code qucikly in less than 15 minutes. Here is C++ for the algorithm.


Using stack


The really important tips are to use stack, so the time complexity can be implemented using O(n) time to parse the infix expression. And the binary express tree can be built in bottom up way. The similar idea using stack can be see in multiple places.

The ) bracket is used to determine when to pop the stack and handle the operand and also operator.


Here is the gist I created how to use stack to parse the infix expression and then construct the binary expression tree.

Here is the output of stack working on a simple test case:

My bet was wrong


 I knew that stack is used on reverse polish notation. And it is widely used to parse the input. There is a hard level algorithm Leetcode 301 to parse parentheses, I did write 10 blogs on that. I also did work on hard level algorithm using more than 10 ideas.

 But the performance on 30 minutes is beyond my control. I could not think clearly using stack and stop on close bracket ), and then start to pop and then construct binary express tree from bottom up.

 What I did is to think about finding operator (1 + 2) so that I can use the string manipulation to get the result. I am not aiming highest potential I can reach in those 30 minutes.

 Through the performance, I understood that it is very important for me to calm down, and list all the options I have. Stack or not using stack, what is time complexity? Can I beat other people to write an optimal time complexity solution.

 I still remembered that I practiced a hard level algorithm on hackerrank and learn the power of using stack. The algorithm is called Reverse shuffle merge.

Actionable Items


Review all past practice using stack.

Here is the first one, Leetcode 109: convert sorted list to binary search tree.

Review one of solution using O(n) time O(1) space, the link is here.



Follow up


Most important is to understand the space is cheap, using space to expedite the time is always best choice, need to scale the problem in large expression. This time I failed to give it a try in 30 minutes using stack to get linear time complexity.

Monday, July 31, 2017

Leetcode 301: Remove Invalid Parentheses

July 31, 2017

Plan to work on the hard level algorithm called "Remove Invalid Parentheses". Spent over 2 hours to study the leetcode discussion, and figured out what to work on. The most important is to write code using other people's ideas, Julia found one person to summarize the solutions  through the discussion. Julia likes to apply Terse, Expressive, and Do one thing  (TED) principle she learned through pluralsight.com course clean code. She likes to go over the handout of the course and apply some notes to her practice. The handout link is here.

Three code principles are outlined in the article called "3 Core Principles to Write Clean Code".

Depth first search I


1. Plan to study Java solution provided by a Google engineer first. Here is the link.

Spent over 2 hours to study the code, Julia wrote one with three test cases. Here is her C# code. Use readable function name, C# code is here.

Depth first search II



2. Plan to study Java solution provided by dietpepsi. Here is the link.

Spent over 2 hours to study the code, Julia wrote one with three test case. Here is her C# code.

The design idea is to scan the string twice, first scan is to remove the invalid ')'; then reverse the string with removed invalid ')', in other words, scan right to left virtually; this time is to remove invalid '('.

After removing invalid ')' and '(', reverse the search and then add to valid strings list.

Breadth first search ( no pruning )


Plan to study the discussion, the link is here. 

C# practice code is here. 

Breadth first search ( pruning )




Plan to study the BFS solution written in Java. The link is here.

A few ideas are applied to prune the BFS algorithm.

Julia's C# practice is here.

4. Plan to read this review of all solutions. The discussion link is here.

5. Plan to study the analysis written in Chinese:

对于一个字符串,在任何时候如果 ')' 的个数多于左括号,则说明从开始到现在位置必然可以删除一个')'.而这段子串可能包含多个')',删除哪一个呢?当然删除任何一个都可以.

例如对于()())(),从开头到 s[4] 位置构成的子串多了一个右括号,因此我们需要删掉一个,而这个子串有三个右括号,但是只会产生2个结果,也就是会有一个重复值.所以在删除括号的时候,为保证不会产生重复值,需要记录一个最后删除的位置,这样可以使得在接下来删除的时候只删除这个位置之后的值.这样我们可以使得当前这一段子串不再包含多余的右括号了.这样我们可以删除了一个右括号之后合法的子串与后面还没有检查过的子串组成一个新的字符串重新开始检查.直到不再含有非法的右括号.

但是还有一种情况是包含了多余的左括号,一种直观的方法是从右向左再按照上面的方法处理一遍左括号.但是将数组逆置之后就可以重用上面的算法了.

所以总的思路就是先对字符串进行处理使得其不再含有非法右括号,然后将其翻转以后再检查是否含有非法的左括号.最后左右括号都检查完之后都合法就是我们要的答案了.

时间复杂度应该是O(n^2).

Plan to study C++ source code. Here is the link. The blog link is here. 

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; 
        }
    }
}


Wednesday, February 7, 2018

Tuesday, July 17, 2018

Leetcode algorithms

July 17, 2018

Introduction


I like to spend one hour to go over those Leetcode algorithms. Leetcode 113, 125, 269, 301, 273, 387, 493, 721.




Wednesday, February 7, 2018

Leetcode 301: Remove invalid parentheses (VI)

Feb. 7, 2018

Introduction

It is interesting to read and study the solution based on breadth first search. Here is the gist I prepared for my study.

It is time for me to warmup the skills using Queue to solve an algorithm. Here is the C# code.


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. 

Wednesday, February 7, 2018

Leetcode 301: Breadth first search and pruning (VIII)

Feb. 7, 2018

Introduction


It is interesting to read the gist I prepared for the discussion of breadth first search and how to prune the algorithm. Here is the link. And here is the C# code.


Leetcode 301: remove invalid parentheses (III)

Feb. 7, 2018

I like to review the study note later for this algorithm. It is written in Chinese. Here is my gist file.


Wednesday, July 18, 2018

Leetcode 301: remove invalid paretheses

July 18, 2018

Introduction


It is hard level algorithm and I have to review the algorithm first. Most of important is that I have to understand how to write working code, and then pass online judge. I reviewed one of submissions I did more than 6 months ago.

Most of important is to write a story how to solve the problem using test case "()())()". I found this test case through my last submission. I have to explain my solution based on this test case.

Story first, code follows


I have to write a story how to work on the test case, I have to write a story. And then I need to conduct time complexity as well.

I put the story in the function specification. I reviewed the code and made some changes.


Here is the code.


Explain how I will solve the problem using test case "()())()", and the valid strings are "()()()" and "(())()".

And based on the test case, explain the time complexity of the algorithm. For example, first part of string is "()())()", second part is same string, how many valid strings we have.



Follow up


July 20, 2018

In order to figure out time complexity, I like to work on the test case with string ()())() repeating twice like ()())()()())(). How many valid string can we generate?

Based on my last practice, the string ()())() is removed extra close parathese and there are two valid strings. One is ()()() and another one is (())().

For first valid string ()()(), concatenated by ()())(), how many valid strings can be generated?
()()()()())()
       
When I work on the extra close paratheses, there are five options to remove ). So there are five valid strings:

(()()()())()
()(()()())()
()()(()())()
()()()(())()
()()()()()()

so in total there are 10 valid strings.

We like to find the upper bound of number of valid strings. Each substring ()())() has two valid string, but the concatenation of two generates 10 valid strings, not just 2 * 2.

I used to be math major. I like to figure out the upper bound. I do like to get more experience on a concrete example. My understanding is that I may have barrier to think clearly about the problem since I do not have any good experience on one test case.

It is time for me to build a good test case and write down some learning here.


Try to explain 



There is new case to remove extra close paratheses. In the first string, two extra paratheses instead of one can be removed. We know that ()())() string at least one close parathese should be removed.

The extra user case explains there are extra 6 valid string available after concatenating two strings. There are three options to remove two close parentheses.

Saturday, October 13, 2018

Does my failure on Leetcode 150 easy level algorithms has a name?

Oct. 13, 2018

Introduction


It is time for me to spend 10 to 30 minutes to go over those failed submissions on 150 easy level algorithms. I like to identify what I should be careful, the growth pain of the algorithm and data structure problem solving. Like a baby growing up in the first year, there are numerous stages an infant can continuously develop. This is the first time I intensely work with the online judge, and work with those problem statements and problem setters, and also work with those hidden test cases which may never be released but may explode any time.

Common mistakes 


I make common mistakes very often. I just could not believe that I learn so much and so quickly through those easy level algorithms.

Sometimes the algorithms are labelled by the mistake as an easy level, but then I just fell in love with the algorithms and continue to learn from my experience. I choose the algorithm to be my mock interview algorithms more than five times.

Most surprisingly I learn a few solution with such elegant solution. I just could not believe that I need to refine my thinking process, and then rework the problem after my first submission by working independently.

I will list over 5 mistakes and lessons I learn in the following later.

687. Longest univalue path with design flaw, pass 43 out of 68 test cases
687. Longest univalue path copy the idea from most popular post
Array easy level algorithms (solved 44, shared 24)

867. Transpose matrix - pass 29/36 test cases
Math easy level algorithms (solved 27/ 32, shared 12)

415. Add Strings recursive version - memory limit exceeded
415. Add Strings Iterative solution - learn to use for loop creatively
String easy level algorithms (solved 32, shared 15) 
680. Valid Palindrome II 418/460 test cases passed Time limit exceeded
686. Repeated String Match memory limit exceeded for last test case
686. Repeated String Match memory limit exceeded for last test case
Hashtable easy level algorithm (solved 25, shared 21)

204. Count Primes verbose code
204. Count Primes elegant version

242. Valid Anagram One more mistake to remind me to work on easy level

500. Keyboard Row do it myself
500. Keyboard Row use HashSet API IsSubsetOf

645. Set Mismatch first submission - XOR
645. Set Mismatch elegant one using XOR two places
645. Set Mismatch use bit manipulation trick

720. Longest Word in Dictionary use hashset
720. Longest Word in Dictionary use Trie data structure
720. Longest Word in Dictionary use Trie data structure
720. Longest Word in Dictionary use Queue data structure
720. Longest Word in Dictionary use recursive function
Medium level (solved 53, shared 4)


915. Partition Array into Disjoint Intervals use three iterations
915. Partition Array into Disjoint Intervals one pass idea discuss
916. Word Subsets using counting sort
916. Word Subsets discuss
918. Maximum Sum Circular Subarray pass 98/108, in the contest
918. Maximum Sum Circular Subarray after the contest, working code
919. Complete Binary Tree Inserter O(1) insert
919. Complete Binary Tree Inserter Using Queue
919. Complete Binary Tree Inserter Using Queue
923. 3Sum With Multiplicity
923. 3Sum With Multiplicity dynamic programming solution 
Medium level tree algorithms (solved 14, total 39, shared 12)

102. Binary Tree Level Order Traversal submitted in 2015
102. Binary Tree Level Order Traversal submitted in 2018
Hard level (solved 33, shared 5)

37. Sudoku Solver
76. Minimum Window Substring One thing a time
85. Maximal Rectangle
239. Sliding Window Maximum optimal solution using LinkedList
239. Sliding Window Maximum All submissions, SortedSet, timeout

A name


I like to give those mistakes a name to encourage myself to work hard, work on more algorithm problem solving.

The name is called in Chinese, "这需要托大家的福,托大家的福就要吃百家饭、穿百家衣". The custom is to help raise a healthy child to eat and wear in so many families. The link is here.


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;
        }
    }
}