Friday, June 21, 2019

I love my failure - timeout code on 518 Coin change 2

June 21, 2019

Introduction


It is so easy to write a dynamic programming solution for Coin change 2. But I spent over one hour to mess with a bug and then fixed the code, my solution has timeout issue. What should I do at the very beginning? Design, show concern about time efficiency, dynamic programming bottom up, more case study on example.


Efficiency


I spent time to learn how to write basic things like copy list using C#, copy list with nested list using C#. I have so much fun to work on them, and I like to write a blog to share it as well.

But in reality I should spend time to learn more important things.

I love to solve a complicated problem. I learn a few things through my practice. Here is the post.

Every day I need to write some code to warm up, even though the code fails to pass online judge, but I enjoy to implement the idea, and learn from the failure.

Here is the link.

C# First practice with timeout issue in 2019

It is a good practice since I have to learn how to write a List<List<int>> and also make the copy list work without using same address in the nested list.
Here are highlights:
  1. The idea is to brute force all possible sequences, including duplicate ones first;
  2. Next step is to remove the duplicate ones by looking up hashset including all keys for each sequence.
Here are failed test cases caught by online judge, I was surprised to learn that I need to work on those issues one by one.
  1. 3, [1, 2, 5], the answer should be 2, not 3
  2. 0, [] should be 1, not 0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _518_Coin_Change_2
{
    class Program
    {
        static void Main(string[] args)
        {
           // var result = Change(3, new int[]{1, 2, 5}); // should be 2
           // var result2 = Change(5, new int[] { 1, 2, 5 }); // should be 3
            var result3 = Change(3, new int[]{2});
        }

        /// <summary>
        /// 518 coin change 2
        /// first get all sequences with duplicate first, and then
        /// remove duplicate count 
        /// 
        /// Time out: 
        /// 500, [1, 2, 5]
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="coins"></param>
        /// <returns></returns>
        public static int Change(int amount, int[] coins)
        {
            if (coins == null || amount < 0)
                return 0;

            if (amount == 0) // caught by online judge: 0,[] should be 1, not 0
                return 1; 

            var F = new int[amount + 1];            
            
            var sequences = new Dictionary<int, List<List<int>>>();
            F[0] = 0;
            sequences.Add(0, new List<List<int>>());

            for (int target = 1; target < amount + 1; target++)
            {
                var newList = new List<List<int>>();
                foreach (var coin in coins)
                {
                    if (coin > target)
                        continue;

                    var search = target - coin;
                    if (!sequences.ContainsKey(search))
                        continue;
                    var list = sequences[search];
                    //var copyList = new List<List<int>>(list); // caught by online judge
                    var copyList = new List<List<int>>();
                    foreach (var subList in list)
                    {
                        var copySubList = new List<int>(subList);
                        copyList.Add(copySubList);
                    }

                    if (copyList.Count == 0)
                    {
                        if (coin == target) // caught by failed test case: 3, [2] should be 0, return 1 instead
                        {
                            var subList = new List<int>(); // caught by debugger
                            subList.Add(coin);
                            copyList.Add(subList);
                        }
                    }
                    else
                    {                        
                        foreach (var sublist in copyList)
                        {
                            sublist.Add(coin);
                        }
                    }

                    newList.AddRange(copyList);
                }

                sequences.Add(target, newList);
            }

            var result = sequences[amount];
            // now it is time to remove duplicate count 
            var hashset = new HashSet<string>();
            int count = 0; 
            foreach (var subList in result)
            {
                // counting sort
                var values = new int[coins.Length];
                var lookupMap = new Dictionary<int, int>();
                for (int i = 0; i < coins.Length; i++)
                {
                    lookupMap.Add(coins[i], i);
                }

                foreach (var value in subList)
                {
                    values[lookupMap[value]]++;
                }

                var key = string.Join("-", values);
                if (hashset.Contains(key))
                    continue;
                hashset.Add(key);
                count++;
            }

            return count; 
        }
    }
}

Case study: My Key Large portfolio performance in a day


Thursday, June 20, 2019

518. Coin Change 2

Here is my discussion post.

It is challenge to find all possible coin change and also avoid duplication. How to remove duplication? I like to do a case study on example 5, coins = [1, 2, 5] and then figure out how to do the work.
Case study 5, [1, 2, 5]
I like to work on example, amount = 5, coins = [1, 2, 5], all coin changes are the following 4 groups,
5 = 5
5 = 2 + 2 + 1
5 = 2 + 1 + 1 + 1
5 = 1 + 1 + 1 + 1 + 1
The reason I like to case studay the example because I studied one of solution using dynamic programming and memoization technique.
First, sort all coins in ascending order, so coins = [1, 2, 5].
Now we like to brute force all possible solutions for minimum coin value.
There are three cases, minimum coin is 1, or 2, or 5.
For each case, we like to solve the problem using subproblem,
5 = 5
5 = 2 + 2 + 1
5 = 2 + 1 + 1 + 1
5 = 1 + 1 + 1 + 1 + 1
Minimum coin value
The above four group can be put into two groups; one is minimum coin value is 1, the second one is minimm coin value 5.
The minimum coin value is 1:
5 = 1 + 1 + 1 + 1 + 1
5 = 1 + 1 + 1 + 2
5 = 1 + 2 + 2
The minimum coin value is 5:
5 = 5
In order to solve the problem, I have to memorize two things, first is to brute force all minimum coin value in ascending order; inner loop is to exhaust all possible count of minimum coin used in the coin change.
minimum coin value has three options, 1, 2, 5.
For the minimum coin value = 1, there are five options, 1, 2, 3, 4, 5 of coin value = 1;
Subproblem definition
Amount = 5, Coins = [1, 2, 5]
F(Amount, Index)
Case 1: minimum coin is 5, index = 2
We only can use coin 5 to make value 5, so
F(0, 2) = 0
F(1, 2) = 0
F(2, 2) = 0
F(3, 2) = 0
F(4, 2) = 0
F(5, 2) = 1
Case 2 : minimum coin is 2, index = 1
F(0, 1) = 0
F(1, 1) = 0, the result is 2
F(2, 1) = 1
F(3, 1) = 0
F(4, 1) = 1, the result is 2 + 2
F(5, 1) = 0
Case 1: minimum coin is 1, index = 0
The idea is to use combinatorics knowledge to solve it first, and then translate the idea into C# code.
To avoid duplicated calculation, we like to define the subproblem F(amount, index), amount is the sum, index is the index of coin array.
Here is the code I chose to study. I like to write some study notes to help me learn the algorithm quickly.
public class Solution {
    /// <summary>
        /// June 20, 2019
        /// study code 
        /// https://leetcode.com/problems/coin-change-2/discuss/99239/C-DFS-with-memorization-of-course-DP-is-better
        /// </summary>
        /// <param name="amount"></param>
        /// <param name="coins"></param>
        /// <returns></returns>
        public int Change(int amount, int[] coins)
        {
            // order coins in order to prune recursion
            Array.Sort(coins);

            // init memorization to -1 (unvisited)
            var map = new int[amount + 1, coins.Length];

            for (int i = 0; i < map.GetLength(0); i++)
            {
                for (int j = 0; j < map.GetLength(1); j++)
                {
                    map[i, j] = -1;
                }
            }

            // DFS
            return CountUsingDepthFirstSearch(coins, amount, 0, map);
        }

        /// <summary>
        /// depth first search
        /// </summary>
        /// <param name="coins"></param>
        /// <param name="amount"></param>
        /// <param name="index"></param>
        /// <param name="map"></param>
        /// <returns></returns>
        private int CountUsingDepthFirstSearch(int[] coins, int amount, int index, int[,] map)
        {
            if (amount == 0)
            {
                return 1;
            }

            if (index == coins.Length)
            {
                return 0;
            }

            if (map[amount, index] != -1)
            {
                return map[amount, index];
            }

            int count = 0;
            for (int i = index; i < coins.Length; i++)
            {
                if (coins[i] > amount) break;

                // using this coin as many times as possible before going to next coin
                int times = 1;
                while (times * coins[i] <= amount)
                {
                    var nextAmont = amount - times * coins[i];
                    count += CountUsingDepthFirstSearch(coins, nextAmont, i + 1, map);
                    times++;
                }
            }

            // memorize
            map[amount, index] = count;
            return count;
        }
}

10 Year Treasury Rate - YCharts

Here is the article to read.


Wednesday, June 19, 2019

The last two times the S&P 500 did this, the market topped out

Here is the link.

The markets are having their best month since January.
But those gains have also pushed the S&P 500′s price-to-earnings ratio close to 17 times forward earnings, a valuation level that marked the top in May and last fall.

what is forward earnings? 

for the S&P 500,” Stockton said Monday on CNBC’s “Trading Nation. ” 
The S&P 500 is within 1% of hitting its 2,940 resistance level. It last touched above that level in early May.

There are enough positive catalysts in the market to keep the rally going, though challenges do remain, says John Petrides, portfolio manager at Point View Wealth Management.

“Where interest rates are and where inflation is, we still have room to run. I think we’ve been marinating one year now on tariffs and the earnings season upcoming is going to let us know if companies are able to navigate through the higher costs from tariffs given the slowdown in the global economy,” Petrides said during the same segment.

A potential rate cut from the Federal Reserve could push stocks higher, Petrides says, though the central bank needs to be clear on the reason behind any move.

“The market is already starting to bake in a 25-basis-point cut by the Fed but if they do 50 basis points and really surprise the market, then I do think stocks can go higher, assuming that the language isn’t the Fed is cutting 50 basis points because they see a pending recession,” said Petrides.

The Federal Open Market Committee convenes on Tuesday for a two-day meeting, culminating with a Wednesday afternoon decision. Markets anticipate a 25-basis-point cut at the July meeting, according to the CME Group fed funds futures.


Case study: My Key Largo portfolio on Ameritrade.com IRA

June 19, 2019

Introduction


It is my personal finance research. I was so ashamed of myself to only make $3,000 gain from 1998 to 2019 with total investment $16,000 dollars, I push myself to build a portfolio in less than one month, now the gain is $400 US dollars. I like to do a case study, and think about rebalance.


Case study


It is important for me to take some time to work on my personal finance. I like to spend time to sell 1 share VOO ETF and then purchase BND bond ETF.


Here is the blog I documented my purchase in June 2, 2019.

Docusign - a great company to do a case study

June 19, 2019

Introduction


It is my short study, I compare two public companies, one is I know long time called Ultimate Software, the second one is Docusign. I got contacted by the recruiter from Docusign first time in my life. I just could not believe it.

Case study


I like to spend time to study the public company, and also I like to push myself to learn about USA economy.

Follow up

June 22, 2020

I should purchase 100 share of Docusign stock. Now it is three time more compared to June 19, 2020.

Case study: My Victoria portfolio on questrade.com

June 19, 2019

Introduction


It is my personal finance research. I was so busy but I still made it happen. I set up my Vitoria portfolio less than one month ago. Now it is time for me to review, the return of $460.00 dollars in less than one month, should I rebalance to buy low and sell high?

Case study




Ideas to rebalance portfolio?


I like to sell 10 shares of VFV.TO, and then purchase VAB bond ETF. I like to buy low and sell high. 

Here is the blog I documented on June 4 to setup my portfolio.



Uber Is Going Public: How Today’s Tech I.P.O.s Differ From the Dot-Com Boom

Here is the link.


Fed scraps its 'patient' interest rate approach in prelude to potential cut

Here is the link.

I have to push myself to read more about personal finance and news related to stock market.

Investors have been betting the Fed will reduce rates at its next meeting in late July, though a majority of economists surveyed earlier this month don’t expect a move until December.

Facebook's digital wallet project head speaks with CNBC

Here is the link.


Tuesday, June 18, 2019

FLAG高频精选面试题讲解 - 31 algorithms

June 18, 2019

Here is the link.

17 Letter combinations of a phone number
23 Merge K sorted lists (hard level)
33 Search in Rotated Sorted array
56 Merge intervals
75 Sorted Colors
76 Minimum window substrings (hard level)
91 Decode ways 
124 Binary tree max path sum (hard level)
138 Copy list with random pointer
161 One edit distance


199 Binary tree right side view
200 Number of islands
219 Contains duplicate II (Easy)
220 Contains duplicate II
224 Basic Calculator (hard)
243 Shortest word distance
244 Shortest word distance II
245 Shortest word distance III
277 Find the celebrity
309 Best time to buy and sell stocks with cooldown

322 Coin change
450 Delete node in BST
481 Magical string
496 Next great element I
503 Next great element II
516 Longest palindromic subsequence
518 Coin change 2
560 Subarray sum equals K
632 Smallest range ( hard level)
652 Find duplicate subtrees


692 Top K frequent words

Algorithms to work on after Leetcode 377 combinations IV

I like to go over those Leetcode algorithms:

39, 40, 216, 322, 518, 474.

Leetcode 39: combination sum ( medium level)
Leetcode 40: combination sum II (medium level)
Leetcode 216: combination sum III (medium level)
Leetcode 322: coin change (medium level)
Leetcode 518: coin change 2 (medium level)
Leetcode 474: Ones and Zeros (medium level)

1090. Largest Values From Labels

1090. Largest Values From Labels C# Try to solve using greedy algorithm practice in 2019

It is one of medium level algorithms in the contest. The greedy algorithm may work out fine.
Here are highlights:
  1. Use SortedDictionary to save all values and their label into SortedDictionary, the key of hashMap is the value, the value of hashMap is list of labels. Since the same value for same label may have duplicate, List is used to store labels;
  2. Get all keys in SortedDictionary and save into the array; Iterate one by one using descending order;
  3. Fail test case II (see function RunTestcase2()), I have to learn how to break two loops instead of one.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _1090_largest_value_from_labels
{
    class Program
    {
        static void Main(string[] args)
        {
            RunTestcase2();
        }

        public static void RunTestcase1()
        {
            var values = new int[] { 5, 4, 3, 2, 1 };
            var labels = new int[] { 1, 1, 2, 2, 3 };

            var result = LargestValsFromLabels(values, labels, 3, 1);
            Debug.Assert(result == 9);
        }

        public static void RunTestcase2()
        {
            var values = new int[] { 5, 4, 3, 2, 1 };
            var labels = new int[] { 1, 3, 3, 3, 2 };

            var result = LargestValsFromLabels(values, labels, 3, 2);
            Debug.Assert(result == 12);
        }

        /// <summary>
        /// 1090 largest value from labels
        /// Use greedy algorithm to solve the problem
        /// Try to simplify the algorithm and do not think generic case
        /// </summary>
        /// <param name="values"></param>
        /// <param name="labels"></param>
        /// <param name="num_wanted"></param>
        /// <param name="use_limit"></param>
        /// <returns></returns>
        public static int LargestValsFromLabels(int[] values, int[] labels, int num_wanted, int use_limit)
        {
            var sortedMap = new SortedDictionary<int, List<int>>();

            var length = values.Length;
            for (int i = 0; i < length; i++)
            {
                var key = values[i];
                var value = labels[i];

                if (!sortedMap.ContainsKey(key))
                {
                    sortedMap.Add(key, new List<int>());
                }

                sortedMap[key].Add(value);
            }

            var usedCount = new Dictionary<int, int>();

            int index = 0;
            var numbers = sortedMap.Keys.ToArray();
            length = numbers.Length;
            var sum = 0;
            var breakLoops = false;
 
            for (int i = length - 1; i >= 0; i--)
            {
                var key  = numbers[i];
                var list = sortedMap[key];

                foreach (var item in list)
                {
                    if (!usedCount.ContainsKey(item))
                    {
                        usedCount.Add(item, 0);
                    }

                    if (usedCount[item] < use_limit)
                    {
                        index++;
                        sum += key;

                        usedCount[item]++;

                        if (index == num_wanted)
                        {
                            breakLoops = true;
                            break;  // there are two loops 
                        }
                    }
                }

                if (breakLoops)
                    break; // caught by online judge, test case 2
            }

            return sum; 
        }
    }
}

1091. Shortest Path in Binary Matrix

1091. Shortest Path in Binary Matrix C# breadth first search practice in 2019


Breadth first search practice in 2019
It is a medium level algorithm. I came out the idea to use queue to do breadth first search, and also mark visited node in case of deadloop.
The problems I came cross are the following:
  1. Read the statement carefully. I think that it should say explicitly that all nodes on the path should have value 0.
  2. Minimum path should also be defined clearly. Count nodes not edges.
I think that the example 2 in problem statement should include a picture to show the path instead of just showing 4 as a result. In the contest, I could not figure out why it is 4. I draw the diagram in the following:
image
The above example 2 the minimum path is 4. So it is counting how many nodes on the path.
Here are highlights:
  1. Design a data structure to store values in Queue, int[] is a good choice. I like to explicitly pass level to express minimum steps from (0,0) to the node;
  2. Breadth first search, I like to apply search one level a time. All next level nodes are saved in the queue first;
  3. Mark visited nodes using original matrix grid to avoid deadloop.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

        /// <summary>
        /// 1091 Shortest path binary matrix 
        /// </summary>
        /// <param name="grid"></param>
        /// <returns></returns>
        public static int ShortestPathBinaryMatrix(int[][] grid)
        {
            if (grid == null || grid.Length == 0 || grid[0].Length == 0)
                return -1;

            var rows = grid.Length;
            var columns = grid[0].Length;

            if (grid[0][0] != 0 || grid[rows - 1][columns - 1] != 0)
                return -1;

            var queue  = new Queue<int[]>();

            var numbers = new int[] { 0, 0, 1 };
            queue.Enqueue(numbers);
            var maxLength = -1;
            
            // apply BFS, put next level into the queue, 8 possible neighbors
            applyBFS(grid, rows, columns, queue, ref maxLength);

            return maxLength;
        }

        /// <summary>
        /// visit neighbor with value 0, eight neighbors
        /// using breadth first search, use Queue
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="rows"></param>
        /// <param name="columns"></param>
        /// <param name="queue"></param>
        /// <param name="maxLength"></param>
        /// <returns></returns>
        private static void applyBFS(int[][] grid, int rows, int columns, Queue<int[]> queue, ref int maxLength)
        {
            if (queue.Count == 0)
                return;
            
            while (queue.Count > 0)
            {
                var count = queue.Count;
                int index = 0;

                while (index < count)
                {
                    var numbers = queue.Dequeue();
                    var row    = numbers[0];
                    var column = numbers[1];                    
                    var level  = numbers[2];                                      
                    
                    if (row == rows - 1 && column == columns - 1)
                    {
                        maxLength = level;
                        break;
                    }

                    var nextLevel = level + 1; 
                    // put 8 neighbors into queue
                    visitNeighbors(grid, rows, columns, row,     column - 1, queue, nextLevel);  // left
                    visitNeighbors(grid, rows, columns, row,     column + 1, queue, nextLevel);  // right
                    visitNeighbors(grid, rows, columns, row - 1, column,     queue, nextLevel);  // up
                    visitNeighbors(grid, rows, columns, row + 1, column,     queue, nextLevel);  // down
                    visitNeighbors(grid, rows, columns, row - 1, column - 1, queue, nextLevel);  // left top
                    visitNeighbors(grid, rows, columns, row + 1, column + 1, queue, nextLevel);  // right down
                    visitNeighbors(grid, rows, columns, row + 1, column - 1, queue, nextLevel);  // right top
                    visitNeighbors(grid, rows, columns, row - 1, column + 1, queue, nextLevel);  // left down

                    index++;
                }
            }
        }

        /// <summary>
        /// mark visited using -1 and save the value in grid matrix
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="rows"></param>
        /// <param name="columns"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        /// <param name="queue"></param>
        /// <param name="level"></param>
        private static void visitNeighbors(int[][] grid, int rows, int columns, int row, int column, Queue<int[]> queue, int level)
        {
            if (row < 0 || row >= rows || column < 0 || column >= columns || grid[row][column] < 0 || grid[row][column] != 0)
                return;

            var numbers = new int[] { row, column, level };

            grid[row][column] = -1; // mark visited

            queue.Enqueue(numbers); 
        }
    }
}