Showing posts with label algorithm. Show all posts
Showing posts with label algorithm. Show all posts

Wednesday, July 17, 2019

76. Minimum Window Substring

Here is my discussion post.

It is challenging task to design a sliding window which has intelligent way to keep count all chars in sliding window no matter whether the char is in pattern string t. I choose to write a solution based on the video shared by Daniel Su.
Small case stduy
S = "ACBA", t ="AB",
There is step by step explanation in the above video using the above test case. I also like to explain the design.
About right pointer in sliding window
if the char on position of right pointer has bank value bigger than 0, then the char is counted towards to be one of chars in pattern t. Variable count decrement one, no matter right char is in pattern string t, bank count will always decrement one.
About left pointer in sliding window
It is similar idea to hanlde left pointer. The argument is if bank[leftChar] > 0, then one of chars in pattern string s is removed from sliding window, count variable should decrement one.
Why it is hard level algorithm?
  1. Fact 1:
work on test case
s = "ABBB", t = "ABB", the pattern string may have duplicate chars. So the sliding window should contain all unique chars and also its count for each char. The minimum sliding window should contain all unique chars in pattern string, and also keep at least same count for each char as well.
  1. Fact 2:
    How to determine if the string in sliding window contains (denoted as sw) all chars in pattern string s?
counting sort all chars in sw and s, and then compare each char and its count. This takes O(k) time, k is distinct chars in pattern string t. It can be O(1) time instead.
How to design the technique to make it O(1)?
For example, S = "ACBA", t ="AB".
Char C's bank value from 0 to -1, and then left pointer moves away index = 1, go back to 0. Since C is not in string t, C's bank value will never go beyond 0.
First it is the design in template to document all chars in sliding window using bank array. Even the characters not in pattern string t will be recorded, for characters in pattern string t will be recorded using bank array, since pattern string may have more than one copy of the same char, how to tell which copy of char goes to count of pattern string t.
Next count variable is introduce to keep "the sliding window contains all char and it's count in pattern string t" checking O(1) time.
Five minutes to understand count variable design
It is tough job to design count variable. It took me hours to understand when to increment one to count variable, when to decrement one to count variable.
One thing I can do is to show a simple test case. The solution is not difficult to write at all.
s = "AAB", t = "AB",
I think that the above test case first 'A' is visited, bank['A'] = 1, so count variable should be incremented by one. Second 'A' is visited, bank['A'] = 0, so count variable will not be incremented.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _76_minimum_window_substring_optimal
{
    class Program
    {
        static void Main(string[] args)
        {
        }

        /// <summary>
        /// July 15, 2019
        /// study code
        /// https://www.youtube.com/watch?v=9odu9ImG9oY
        /// </summary>
        /// <param name="s"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public string MinWindow(string s, string t)
        {
            if (s == null || s.Length == 0 ||
                t == null || t.Length == 0)
            {
                return "";
            }

            var bank = new int[256];
            
            int left = 0;
            int right = 0;
            int count = 0;

            int min = Int32.MaxValue;
            string minString = "";

            var pLength = t.Length;
            var length = s.Length;

            for (int i = 0; i < pLength; i++)
            {
                bank[t[i]]++;
            }

            while (right < length)
            {   
                var rightChar = s[right];
                right++; // always advance one to next iteration 
                if (bank[rightChar] > 0)
                {
                    count++;
                }

                bank[rightChar]--; // always decrement one no matter char is in pattern t or not                              

                // move left pointer until missing one char from string t
                while (count == pLength)
                {
                    var size = right - left;
                    if (min > size)
                    {
                        min = size;
                        minString = s.Substring(left, right - left);
                    }

                    // shift our window
                    var leftChar = s[left];
                    left++;  // always move left pointer
                    bank[leftChar]++; // always increment one no matter char is in pattern t or not                    

                    if (bank[leftChar] > 0) // that means left char is one of chars in pattern, also count as one
                    {
                        count--;
                    }
                }
            }

            return minString;
        }
    }
}


Sunday, September 13, 2015

Leetcode 106: construct binary tree from inorder and post order traversal

Sept. 13, 2015

 Spent more than a few hours to work on the leetcode problem, and my favorite blogs about this problems:

 1. http://siddontang.gitbooks.io/leetcode-solution/content/tree/construct_binary_tree.html

 2. http://blog.csdn.net/linhuanmars/article/details/24390157

 After reading the above reference 1, Julia spent first few hours to write the C# implementation:

 https://github.com/jianminchen/Leetcode_C-/blob/master/106ConstructuBTreeFromInorderPostOrderTraversal.cs

  In her coding practice of function build(...), she spent over 20 minutes to figure out the coding task: the code to partition the inorder traversal into two partitions, first is left subtree, second is right subtree. And then, post order traversal also can be partitioned into two intervals, first one is for left subtree, and then, second one is for right subtree.

  She took more than 10-15 minutes to understand the solution. That is too long for real problem solving. Figure out that only job is to find the root node, and then, its left child and right child is also the root node of left subtree/ or right subtree. The recursive call, actually two of them, can help to do the task.

  So, she needs to cut down the practice time, and make sure the calculation is correct, easy to tell/ maintainable code/ testable code. So, she decided to practice it using class Range instead of two arguements start/ end integers. Hopefully, this practice will enhance her memory about partition the array into two parts, one is dividing in mid point, another one is by length of first interval - left subtree.

public class Range{
public int start, end;
...

}

  Also, she likes to enhance her memory about this solution, so, she writes second implementation using C#, and see if the code can pass online judge. Most important, she tried to use different solution, to improve, challenge herself. Write the code without any mistake first time, in less than 10 minutes based on previous one.

 https://github.com/jianminchen/Leetcode_C-/blob/master/106ConstructBTreeFromInOrderPostOrderTraversal_B.cs

  Julia likes to train herself using leetcode questions, and biggest problem is to cut down the time to write a solution. She tries to cut down time from hours to 10-30 minutes.

  After the code writing, she thought about more about great ideas out there, she should not miss. So, she reads the second reference, and like the most about the analysis:
"这道题和Construct Binary Tree from Preorder and Inorder Traversal是树中难度比较大的题目了,有朋友可能会想根据先序遍历和后序遍历能不能重新构造出树来,答案是否定的。只有中序便利可以根据根的位置切开左右子树,其他两种遍历都不能做到,其实先序遍历和后序遍历是不能唯一确定一棵树的,会有歧义发生,也就是两棵不同的树可以有相同的先序遍历和后序遍历,有兴趣的朋友可以试试举出这种例子."

  Julia 发现在训练自己做题是, 如果能摸索出方法, 提高写代码的速度, 从几个小时, 到10-30 分钟, 那就是很成功的训练. 一种方式, 就是, 找到她喜欢的题解, 能够理解算法; 接下来, 看如何提高写代码的速度, 最好的方式, 就是多写几个解法, 看哪个不容易出错. 

 最后, 就是, 快速看十几个博客, 看有没有错过最重要, 最关键的分析. 

 接下来, 就是重复训练; 分析超时的原因, 能不能达到目的10-15分钟写出正确的代码. 就像网球训练, 训练自己. 



Thursday, September 10, 2015

Backtracking algorithm: rat in maze

Sept. 10, 2015

  Study again the back tracking algorithm using recursive solution, rat in maze, a classical problem. Made a few of mistakes through the practice, one is how to use two dimension array, another one is that "not all return path returns value", not so confident that "return false" at the end of function.

  重温二年前做过的算法题, Rat in Maze, 为自己惭愧! 二年前的练习, 没有任何的参考网页信息, 也没有算法讨论, 尝试改进. 感觉到自己的差距, 这次练习, 着重强调把算法能背出来. 一步一步写出来, 发现几个错误. 二维数组不熟悉, 耽误了十几分钟; 另外, 就是, "return false" 在递归函数最后一句, 先是忘了. 总之, 这个经典题目, 十分钟写不出来; 需要二个数组, 边界条件检测, 一点印象没有.

  Here are my favorite blogs about this problem:

1. http://www.geeksforgeeks.org/backttracking-set-2-rat-in-a-maze/

2. http://algorithms.tutorialhorizon.com/backtracking-rat-in-a-maze-puzzle/

3. https://www.cs.bu.edu/teaching/alg/maze/


  Julia's C# pratice:

  https://github.com/jianminchen/AlgorithmsPractice/blob/master/RatInAMaze_BackTracking.cs

  And then, try to find more discussion about this problem, came cross blogs to challenge my analysis skills. 搜一下Google, 找到一个很有深度的网页, 看了以后, 体验一下代码, 感觉比自己的水平高了几个档次.

  http://blogs.msdn.com/b/mattwar/archive/2005/02/03/366498.aspx

  http://blogs.msdn.com/b/mattwar/archive/2005/02/11/371274.aspx

  More code to read and then play:

http://www.evercrest.com/ext/CheeseAppropriator.cs

  and C# practice:

https://github.com/jianminchen/AlgorithmsPractice/blob/master/MousingAround.cs

January 10, 2016
Review the algorithm

Follow up 

April 27, 2017

Draw a circle algorithm

August 18, 2015
Interesting problem – draw a circle,
blogs to read:
C# code I wrote in Dec. 2012 is here

Follow up 


January 23, 2018

I traced my outlook email and then I found out that it is one of my phone screen algorithm I got in 2012. I supposed to write in 20 - 30 minutes, and at most 40 - 50 minutes.  

"More detail about the draw circle program, in first 10 minutes, I came out a mediocre solution, an then I tried to catch up while coding to put more ideas in, so I changed the original idea to set a target, and then made this 1000 tries to reach the target; the algorithm is like an undetermined optimal algorithm, with a lot of mistakes, losing the focus sometimes. I should have clarified the requirements with you before I started yesterday and work in the right direction. "

It is such a great feeling to read what I wrote in 2012. It is more than 6 years ago. At that time, I was too shy and I did not have habit to write daily. And I still remembered that I was so excited to have a phone screen, at that time, as a software developer, I was too isolated and my personality was kind of introvert. I was afraid to write down what I think at that time.

C# code I wrote in Dec. 2012 is here. Read the code I wrote more than 6 years ago. How to define the feeling? It is like meeting an old friend, sweet and sour. But this time the sour is mild level, code smells make the sour feeling. 

Code review and then C# code is written, the link is here

Sunday, August 23, 2015

String functions review

August 23, 2015


1. stringDemo.cpp

Including
atoi 5 versions of implementation


2. Scramble string:



3. strstr

Boyer-Moore algorithm

Read the string function website and get ideas:

http://algs4.cs.princeton.edu/53substring/

http://zjalgorithm.blogspot.ca/2014/12/leetcode-in-java-implement-strstr.html

Need a test case to help me figure out Boyer-Moore algorithm again on August 23, 2015.
Here is a short one for me to memorize the idea:
http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/StringMatch/boyerMoore.htm

read the article quickly in 20 minutes on August 23, 2015
http://web.cs.ucdavis.edu/~gusfield/cs224f11/bnotes.pdf

Dec. 12, 2015 video watch:
https://www.youtube.com/watch?v=fHNmRkzxHWs
one of examples the presenter gave in his Cpp conference video.
Know that there is a definitely better algorithm than O(n^2), but also, need to know what the ideas are to beat the naive solution. 

Dec. 11, 2015
Need to work on a small test case, therefore, the algorithm can be easily recalled, and ideas of algorithms can be demoed clearly in the example. Go to find my favorite string, substring. (January 5, 2015, read the wiki page, https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm, read 'The bad character rule' and 'The good suffix rule' )

4. longest palindromic string

5. Look up standard string function implementation, quick review and learn:


January 5, 2016
Read the Java code on the following website:
http://algs4.cs.princeton.edu/53substring/BoyerMoore.java.html

Write a C# version, and check in github, and see if it will help to memorize the algorithm. 

Read the webpage: (well written! now Julia knows two rules: bad character rule, the good suffix rule)
https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm

http://www.cs.tufts.edu/comp/150GEN/classpages/BoyerMoore.html



Tuesday, August 18, 2015

Leetcode question 20 - 30

August 18, 2015

Work on those ten questions quickly, spend 20 minutes on each question; Do not over analyze the problem, try to get basic idea and implementation tips through blogs first.

22 Generate Parentheses

https://github.com/jianminchen/Leetcode_C-/blob/master/GenerateParentheses_No22.cs

23 Merge K Sorted Lists

https://github.com/jianminchen/Leetcode_C-/blob/master/MergeKSortedLists_A_No23.cs

https://github.com/jianminchen/Leetcode_C-/blob/master/MargeKSortedLists_B_No23.cs

24 Swap nodes in pairs

https://github.com/jianminchen/Leetcode_C-/blob/master/24SwapNodesInPairs.cs


C# implementation:
https://github.com/jianminchen/Leetcode_C-/blob/master/24SwapNodesInPairs.cs

25 Reverse Nodes in k-Group

26 Remove Duplicates from Sorted Array

27 Remove Element

28 Implement strStr()

29 Divide Two Integers

30 Substring with Concatenation of All Words



Monday, August 10, 2015

Leetcode: Maximum product subarray

August 10, 2015
Find the contiguous subarray within an array (containing at least one number)
which has the largest product.
For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.
Two approaches, one is dynamic programming DP implementation, another is the greedy method.
DP solution:
Greedy algorithm:
read the blog first,
http://fmarss.blogspot.ca/2014/10/leetcode-solution-maximum-product.html

and then, convert it to C# programming language, 

Tuesday, July 28, 2015

Leetcode Question No 70: climbing stairs

July 28, 2015

Problem statement:
You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

The problem is most popular question in the algorithm, so I do like to spend time to find out all sorts of solution, and get myself comfortable to all kinds of ideas, and figure out which one is best, and all concerns we can have in the discussion of climbing stairs:

1. Recursion solution vs. DP problem solution (Dynamic Programming solution)
2. Time complexity solution: O(2^n) vs O(n) solution
3. The space O(N) vs O(1), in other words: array of N or 2 variable, and another tmp variable
4. The base case discussion: f(0) = 1 or f(0) =1, math question?
5. Math formula - closed form solution vs DP problem solution
6. Use Memoization DP vs. no memoization DP
7. Programming skills, how to make code easy to follow, more readable, more abstract. 

The investment of time on the problem is well done. Go over 16 implementation one by one using C# programming language. 

C# code:

其实, 我觉得题目越容易, 越值得投入时间去学习; 看看大家有没有不同的理解, 打开思路; 如果自己没有训练过这道题, 可能会紧张; 即使训练过, 但是, 有的想法, 可能自己从来没有思考过, 一时还不能判断好坏, 但是, 多看网上的博客, 向每一个人取取经. 谦虚, 才能有提高.

我编网站后台, C#程序自己写; 自己训练的题目太少; 这次选择用Leetcode来提高C#编程, 又可以提高算法和数据结构的知识, 网站后台靠平时训练.  

January 3, 2016
Review the leetcode question 70, climbing stairs. 
Read the blog:
http://blog.csdn.net/kenden23/article/details/17377869
http://yucoding.blogspot.ca/2012/12/leetcode-question-15-climbing-stairs.html

http://www.cnblogs.com/springfor/p/3886576.html

http://www.cnblogs.com/springfor/p/3886576.html

http://siddontang.gitbooks.io/leetcode-solution/content/dynamic_programming/climbing_stairs.html

https://github.com/zwxxx/LeetCode/blob/master/Climbing_Stairs.cpp



Saturday, July 25, 2015

Leetcode 238: Product of Array except itself

July 24, 2015

 Introduction



I like to share the article talking about Google interview written in Chinese. The article is called "死理性派教你做谷歌面试题", the link is here

The experience of working on Leetcode is so challenging. I fully understand the solution but after a few days, I have no clue how it works. But there are so many good articles to read. 

Leetcode 238 in Chinese



  转载上面网页最后一段.

  不同于上面的“流传”,下面两道是已被确认了的google面试题。
第一题,给你一个长度为 N 的链表。N 很大,但你不知道 N 有多大。你的任务是从这 N 个元素中随机取出 k 个元素。你只能遍历这个链表一次,且必须保证取出的元素是完全随机的(出现概率均等)。
第二题,给你一个数组 A [ 1 .. n ] ,请你在 O ( n ) 的时间里构造一个新的数组 B [ 1 .. n ] ,使得 B [ i ] = A [ 1 ] * A [ 2 ] * ... * A [ n ]/A [ i ] 。你不能使用除法运算。
这两道题目看起来很专业,但有趣的是,即使没有学过信息学的人也可以想到答案。
第一题的意思就是有一大串物品,它们能且仅能逐个经过你眼前一次。你不知道它们的个数,要求你从中随机地抽取 k 个物品,同时必须保证取出的元素是完全随机的(出现概率均等)。
第二题给出了一个数列 A [ 1 .. n ] ,要求在较短的时间内不用除法构造一个新数列 B [ 1 .. n ] ,使得 B [i] = A [ 1 ] * A [ 2 ] * ... * A [ n ]/A [ i ] 。 n是这个数组的长度。而 O ( n ) 是评判计算方法速度的标准。如果一个解答方法在n任意变化的情况下,都能满足总共的计算次数相当于是 n 乘以一个常数C这个条件,那么就称这个解答方法是 O ( n ) 的;如果这个解答方法能满足总共的计算次数是 n 2 乘以常数C,那么这个解答方法就被称作是 O ( n 2 ) 的。
第一题没有告诉我们物品的个数N,所以我们没法算出 k/N,连最基本的每样物品被选中的概率都不知道,还怎么继续操作呢?既然我们不知道一共有多少个物品,那我们就应该在所有的物品都经过我们眼前之后再做抉择。当每个物品经过我们眼前的时候,可以设法对应地给它生成一个 0 到 1 之间的随机数。等到我们见过了所有的物品之后,只需要选择对应的随机数最大的前 k 个物品就行了。
第二题不允许用除法增加了不少难度。 B [ i ] 不用除法来表示的话就是: B [ i ] = A [ 1 ] * ... * A [ i - 1 ] * A [ i + 1 ] * ... * A [ n ] 。若按照这个表达式进行计算,生成每个 B[ i ] 的时候要进行n - 1次乘法,这样一来完全生成 B [ 1 .. n ] 就需要 O ( n 2 ) 的时间了。我们需要通过减少重复的运算来提高效率。
注意到 B [ i ] 可以看作是两个部分的乘积, A [ 1 ] * ... * A [ i - 1 ] 和 A [ i + 1 ] * ... * A [ n ] 。同理 B [ i + 1 ] 就由 A [ 1 ] * ... * A [ i - 1 ] * A [ i ] 和 A [ i + 2 ] * ... * A [ n ] 组成。计算 B [ i ] 时的许多乘法在计算 B [ i + 1 ] 的时候又进行了一遍,因此可以重复利用上一次运算的结果,以避免无谓的运算。从这点出发,我们构造两个新的数列:
S [ i ] = A [ 1 ] * ... * A [ i – 1 ]
T [ i ] = A [ i + 1 ] * ... * A [ n ]
因为生成完整的 S [ 1 .. n ] 和 T [ 1 .. n ] 都能在 O ( n ) 的时间内完成,那么根据 B [ i ] = S [ i ] * T [ i ] 这条式子,生成整个 B [ 1 .. n ] 便也能够在 O ( n ) 的时间内完成了。
不得不说,谷歌是个很爱玩的公司。它曾在MIT校园内到处张贴着一份密码,据说,这份密码包含了一个Google Jobs的电话号码,解开密码的人可以通过此电话留下自己的个人信息,进入谷歌工作。各位读者,你能解开这个密码吗?如果有漂亮的解答,我会在这里贴出来。



Thursday, July 23, 2015

Leetcode 102: Binary tree level order traversal

July 23, 2015
Problem statement:
Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).
For example:
Given binary tree {3,9,20,#,#,15,7},
    3
   / \
  9  20
    /  \
   15   7
return its level order traversal as:
[
  [3],
  [9,20],
  [15,7]
]
confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.
写代码发现很多问题. 程序要多写, 多练. 背算法可能也是一个途径. 从C++代码, 转化成C#, 犯了几个错. 一下学习到很多C#知识, 感觉不错! 练习6种方法. 
1. Solution 1: (push extra null node in the queue to divide level)
Read the blog:
convert it to C# code:
C# code passing leetcode online judge:
Solution 2: (using 3 variables to help queue to do BFS algorithm)
blog:
C# code:
Solution 3: DFS algorithm:
blog:
C# code: