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


NextEra stock: How NextEra Overtook ExxonMobil As The Largest U.S. Energy Company

 Here is the link. 

If you had invested in Florida-based utility NextEra Energy NEE +2% a decade ago, your total return through this week, including dividends, would have been 600%. That is a phenomenal return for an energy company.

I bought FPL stock in 2001, but I sold all of them and held less than two years. 

Sunday, October 4, 2020

Intc stock: Intel Stock Is a Tremendous Value at $50

 Here is the article. 

To be fair, Intel did receive a benefit from the corporate tax cut. That’s very real in the sense that it gives the company more profits with which to pay dividends and buy back stock, however it doesn’t reflect improvement in the structural quality of the business.

That said, earnings are up more than 150%; obviously that’s not just tax cuts. Since 2016, Intel’s revenues are up from $59 billion to $72 billion. That’s healthy growth. And management’s pre-Covid guidance saw this climbing to $85 billion annually over the next few years. The idea that Intel is totally stalled out simply isn’t accurate. What’s true is that the CPU business has minimal growth prospects.

However, Intel has diversified well-beyond its most famous operations. Going forward, automotive chips and services (the old Mobileye business) along with nonvolatile memory, programmable solutions, and more can add large chunks of incremental revenue for Intel stock.

Oil stock: Most U.S. Oil Jobs Lost in Pandemic Won’t Return at These Prices

 Here is the article. 

107,000 jobs eliminated 

The collapse in oil demand and prices spurred the fastest rate of oil- and chemical-industry layoffs in history, with about 107,000 jobs eliminated between March and August, Deloitte said in a study scheduled to be released Monday. The number is probably even higher when furloughs and other headcount measures are taken into account, according to Duane Dickson, vice chairman and U.S. oil, gas and chemicals leader for Deloitte.


Deloitte is forecasting a 30% recovery of lost jobs by the end of 2021, assuming oil averages about $45 a barrel and natural gas hovers around $2.50 per million British thermal units. But if crude instead lingers around $35 and gas is more like $2, the jobs-recovery rate probably will only reach 3%, according to the report.

Oil, gas and chemical jobs have become more sensitive to changes in commodity prices as the North American shale revolution turned world energy markets topsy-turvy. A $1 change in oil prices affects about 3,000 oil and gas jobs, double the impact it would have had during the 1990s, according to the report.

Algorithm interview: Find one valid string to remove minimum number of invalid parentheses from a string

 Oct. 4, 2020

Introduction

It is one hour mock interview as an interviewee. I had chance to learn from my own experience, and the interview gave me such great help to analyze time complexity, and I had chance to review my own performance as well. 

Case study of mock interview

Here is the link. 



Interviewee feedback



Interviewer feedback





System design: AWS cloud

 Oct. 4, 2020

Introduction

It is amazing for me to start to practice on pramp.com. I had a system design interview with a peer, and I felt that new generation of software engineers are more hard working and also full of energy. I like to learn from them, and system design is such great learning tool for me to catch up with others. 

Design twitter

Here is my peer's performance. 



My behavior research: My tough finance situation last 10 years

 Oct. 4, 2020

Introduction

It is not easy for me to figure out how to be a good business person to survive in Canada economy. I like to write blogs about this topic. 

My behavior problems

I have some behavior problems. I like to write a series of blogs to look into this issue. How to be a frugal person? How to survive in this economy since coronavirus? How to take care of my own business, and do not fall into traps with others. 

Recently I reviewed my finance problems, and I chose not to talk about my tough situation since coronavirus, hay fever, challenges in my current job etc. 

I choose not to open communication to my siblings. I do believe that hard working will pay off. I choose to be a software programmer, it is not guaranteed and risky job. It is not a job with union, and it is not a stable job like working for government. 

I have to continue to study and work on my algorithm and data structure in order for me to survive. 


Leetcode discuss: 862. Shortest Subarray with Sum at Least K

 Here is the link. 

C# A few steps to solve a hard level algorithm

Oct. 3, 2020
862. Shortest Subarray with Sum at Least K

Introduction
It is important for me to move my focus from easy and medium level algorithm to hard level ones, since I already solved over 500 algorithms and it takes me over 5 years now. I have to start to work on one by one next four weeks to prepare Google phone screen in early November.

Worked on by myself first
I thought about preprocess the array using O(N) time first, so using prefix sum of the array it will take O(1) to calculate any subarray's sum.
In order for me to consider the shortest subarray at least K value, I have to look up previous index value and it's prefix sum. How to find shortest one if there are multiple ones?

What data structure can help to solve the problem? I did not come out the idea using deque data structure, if there are more than one to satisfy at last K value requirement, then the first one in the deque is shortest one for current index - assuming that iteration from start index 0 to last step of prefix array.

In other words, deque will have only one to satify at least K value requirement. And also the first one in the deque should be the candidate.

And also I need to filter out some index which will not be candidate for the start point of subarray to fit into K value requirement, which can be related to deque.

Quick study of discussion post and Leetcode solution
I came cross the solution, and I learn from the reasoning. Here is the link.

I also read the discussion post, but I understand that I will not really learn the algorithm until I can write the code with C# implementation, bug-free, work on a few case study.

C# implementation
I practiced the code and wrote one based on the discussion post here.

Here are highlights of my practice:

  1. Design prefix sum array using length + 1 instead of length of the orginal array;
  2. More on step 1, I failed the test case [2, -1, 2], so prefix array definition is changed to prefix[i] = sum of the array from 0 to i - 1, i is from 0 to length + 1;
  3. I missed deque.Add(i) in my first writing, always go through manual checking - deque, four operations, remove-first, append_back, remove_back, insertion at the back and removal from both end;
  4. Go through prefix sum array one by one, remove from end of deque if the last one will no longer be start of shortest subarray with at least K requirement; Remember a while loop, not once only using if.
  5. Remove start of deque to make sure that if there are more than ones to satisfy at least K value, the first one in deque is shortest one.

Tips to share
Since I spent whole day to learn this algorithm, and also I asked the algorithm in my 10:00 PM mock interview, I like to write down as many tips as I can. So it is easy for me to review the algorithm later.

Work on case study, the array is [2, -1, 2], K = 3, the shortest length is 3. Work on the case and calculate by hand.
Work on case study, the array is [3, -2, 5], K = 4, the shortest length is 1, the subarray is [5].

Segment tree, range sum query is over-engineering for problem solving. I worked on segment tree algorithm, and I asked one question for code review on stackexchange, the algorithm is called kindergarten adventures.

Binary search algorithm based on length of subarray does not work. The interviewee went through the length of binary search, but [3, -2, 5], k = 4, the length = 1, subarray [5]'s sum >= 4, length = 2, non of subarray works, length = 3, [3, -2, 5] with sum = 6 working.

Deque can be implemented using C# LinkedList. Prefix sum array design is hard to work out best design in the first practice.

public class Solution {
    public int ShortestSubarray(int[] A, int K) {
        if(A == null || A.Length == 0)
            return -1; 
        
        var length = A.Length;
        var prefix = new int[length + 1]; // change from length to length + 1 since failed [2, -1, 2]
        
        // using O(N) time to build a prefix sum of the array
        prefix[0] = 0;
        for(int i = 0; i < length; i++)
        {
            prefix[i + 1] = prefix[i] + A[i]; 
        }
        
        var shortest =  length + 1; 
        
        // store index of the array into deque
        var deque = new LinkedList<int>(); 
        
        // three operations of deque
        // remove_front - it is impossible for the start point
        // append_back - it is possible for new start point
        // remove_back - it is impossible for the start point
        
        // check current index and first one in dequeue - prefix difference vs K
        // test case: [2, -1, 2]
        for(int i = 0; i < prefix.Length; i++)
        {
            var current = prefix[i];
            
            // while loop - continuously remove_back
            while(deque.Count > 1 && prefix[deque.Last.Value] >= current)
            {
                deque.RemoveLast();
            }
            
            // missing LinkedList Add?
            deque.AddLast(i);
            
            // remove_front - keep maximum one
            // if start point to current index's difference is at least K, 
            // then start point should be biggest index
            while(deque.Count > 1 && (current - prefix[deque.First.Next.Value] >= K))
            {
                deque.RemoveFirst();           
            }
            
            if( i > 0 && (current - prefix[deque.First.Value] >= K))      
            {
                shortest = Math.Min(shortest, i - deque.First.Value);       
            }
        }
                  
        return shortest == length + 1? -1 : shortest;           
    }
}


Saturday, October 3, 2020

Trello project: Interviewing.io and pramp mock interviews

 Oct. 3, 2020

Introduction

Life is tough as a business woman. I have to make a living and think about how to build wealth. I spent over three months to learn how to invest on stock market. But once I started to work on Google phone screen, next four weeks are most important time for me to learn and work on algorithm, system design and behavior interview preparation. 

Trello project app

I missed 8:00 PM mock interview on pramp.com. It is the first time I set up behavior interview. So I decided to use trello to manage my weekend schedule. 



800 algorithms: Google tagged

 Here is the page. 


Hard level: 862. Shortest Subarray with Sum at Least K

Here is the link. 

Approach 1: Sliding Window

Intuition

We can rephrase this as a problem about the prefix sums of A. Let P[i] = A[0] + A[1] + ... + A[i-1]. We want the smallest y-x such that y > x and P[y] - P[x] >= K.

Motivated by that equation, let opt(y) be the largest x such that P[x] <= P[y] - K. We need two key observations:

  • If x1 < x2 and P[x2] <= P[x1], then opt(y) can never be x1, as if P[x1] <= P[y] - K, then P[x2] <= P[x1] <= P[y] - K but y - x2 is smaller. This implies that our candidates x for opt(y) will have increasing values of P[x].

  • If opt(y1) = x, then we do not need to consider this x again. For if we find some y2 > y1 with opt(y2) = x, then it represents an answer of y2 - x which is worse (larger) than y1 - x.

Algorithm

Maintain a "monoqueue" of indices of P: a deque of indices x_0, x_1, ... such that P[x_0], P[x_1], ... is increasing.

When adding a new index y, we'll pop x_i from the end of the deque so that P[x_0], P[x_1], ..., P[y] will be increasing.

If P[y] >= P[x_0] + K, then (as previously described), we don't need to consider this x_0 again, and we can pop it from the front of the deque.


Pramp.com system design: pastebin

 Here is the link.