Showing posts with label google phone screen 2020. Show all posts
Showing posts with label google phone screen 2020. Show all posts

Wednesday, October 14, 2020

System design: Linkedin profile - Randy Shoup - Microservice architecture

 Here is the link. 

About

I have worked as a senior technology leader and executive at companies ranging from small startups, to mid-sized places, to eBay and Google. I have found that high-performing organizations combine clear goals, supportive culture, efficient organization, and flexible technology. I believe in small multidisciplinary teams, autonomy and accountability, and goals over solutions. Mostly, I believe in doing something you care about with people you like and respect.

I have a broad range of technology interests, and I like a new challenge. So I suppose I have been more or less a serial expert, moving from databases and analytics platforms, to security software, to ecommerce and search, and more recently to cloud infrastructure. One common thread across the last 30 years has been working on highly scalable, highly available, multi-tenant distributed systems serving hundreds of millions of users.

I enjoy sharing my experiences with others through advising and conference speaking. You can find a range of topics covered at slideshare.net/randyshoup, and on my blog at randyshoup.com.
 

Tuesday, October 6, 2020

Leetcode patterns: Google - hard level

 Here are 26 algorithms I like to go over at least once. 

First Missing Positivehttps://leetcode.com/problems/first-missing-positive/
Longest Consecutive Sequencehttps://leetcode.com/problems/longest-consecutive-sequence/
Merge k Sorted Listshttps://leetcode.com/problems/merge-k-sorted-lists/
Smallest Range Covering Elements from K Listshttps://leetcode.com/problems/smallest-range-covering-elements-from-k-lists/
Insert Intervalhttps://leetcode.com/problems/insert-interval/




逆序对问题的基础算法

 Here is the article. 

现在终于可以介绍树状数组(Binary Indexed Tree)。树状数组这个中文名称比英文Binary Indexed Tree好很多,因为树状数组用起来跟普通数组差不多,而对tree进行索引访问很奇怪,如tree[2]=10。树状数组有两个独特性质:

  1. 树状数组设置值的复杂度为O(log n)。
  2. 对树状数组任意区域求和的复杂度为O(log n)。

基于以上特性,我一般在代码中按其功能写成QuickSumArray,而不是Binary Indexed Tree或中文树状数组。


493. Reverse Pairs

 Here is the discussion link I read after I thought about the solution by myself over 10 minutes. 

Hard level algorithms: Life is tough to work with those hard level algorithms

 Oct. 6, 2020

Introduction

I like to invest time to learn 50 hard level algorithms on Leetcode.com. What I like to do first is to learn ideas how to solve them, and seek some good ideas to build strong analytical skills first. 

Hard level algorithms

I have limit time to work on those hard level algorithms, so I like to figure out how to learn better. 


Monday, October 5, 2020

Case study: Find maximum number of living people

 Here is the gist. 


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


Sunday, October 4, 2020

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





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. 



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.