Golang N log N solution
\n// Dynamic Programming with Binary Search\n// Time complexity : O(nlogn). Sorting and binary search both take nlogn time.\n// Space complexity : O(n). dp arra
```\n// Dynamic Programming with Binary Search\n// Time complexity : O(nlogn). Sorting and binary search both take nlogn time.\n// Space complexity : O(n). dp array of size n is used.\nfunc maxEnvelopes(envelopes [][]int) int {\n\t// For each envelope, sorted by envelope[0] first, so envelope[1] is the the longest\n\t// increasing sequence(LIS) problem. When envelope[0] tie, we reverse sort by envelope[1]\n\t// because bigger envelope[1] can\'t contain the previous one.\n\tsort.Slice(envelopes,func(i, j int) bool {\n\t\tif envelopes[i][0] == envelopes[j][0] {\n\t\t\treturn envelopes[i][1] > envelopes[j][1]\n\t\t} else {\n\t\t\treturn envelopes[i][0] < envelopes[j][0]\n\t\t}\n\t})\n\t// dp keeps some of the visited element in a sorted list, and its size is\n\t// length Of LIS sofar. It always keeps the our best chance to build a LIS in the future.\n\tdp := []int{}\n\tfor _, envelope := range envelopes {\n\t\ti := sort.SearchInts(dp, envelope[1])\n\t\tif (i == len(dp)) {\n\t\t\t// If envelope[1] is the biggest, we should add it into the end of dp.\n\t\t\tdp = append(dp, envelope[1])\n\t\t} else {\n\t\t\t// If envelope[1] is not the biggest, we should keep it in dp and replace\n\t\t\t// the previous envelope[1] in this position. Because even if envelope[1]\n\t\t\t// can\'t build longer LIS directly, it can help build a smaller dp, and\n\t\t\t// we will have the best chance to build a LIS in the future. All elements\n\t\t\t// before this position will be the best(smallest) LIS sor far. \n\t\t\tdp[i] = envelope[1];\n\t\t}\n\t}\n\t// dp doesn\'t keep LIS, and only keep the length Of LIS.\n\treturn len(dp)    \n}\n```
['Dynamic Programming', 'Binary Tree', 'Go']