diff --git a/Algorithms/Interesting.Algorithms/morris.traversal.org b/Algorithms/Interesting.Algorithms/morris.traversal.org new file mode 100644 index 0000000..dbb8f6c --- /dev/null +++ b/Algorithms/Interesting.Algorithms/morris.traversal.org @@ -0,0 +1,48 @@ +#+title: Morris Traversal + +A O(1) space, in-order, binary tree traversal algorithm. + +* Tree node definition + + #+begin_src C++ + struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + }; + #+end_src + + Given the root of the tree =root=, traverse the tree using constant space. + +* Basic Idea + + Modify a leaf node's right child to point to it's in-order successor. + + #+begin_src C++ + void morris(TreeNode* root) { + while(root) { + if (!root->left) { + visit(root); + root = root->right; + } else { + TreeNode* t = root->left; + while(t->right && t->right != root) t = t->right; + if (!t->right) { + // update t->right to point to root + t->right = root; + root = root->left; + } else { + // visited all root->left tree + visit(root); + t->right = nullptr; + root = root->right; + } + } + } + } + #+end_src + +* Application + C++ destructor of a Tree may cause stackoverflow if the tree is not well balanced if we recursively call the destructor of each children. + Using Morris Traversal can eliminate this problem + diff --git a/Algorithms/Leetcode/0042.trapping.rain.water.org b/Algorithms/Leetcode/0042.trapping.rain.water.org index e99d63f..2783cdf 100644 --- a/Algorithms/Leetcode/0042.trapping.rain.water.org +++ b/Algorithms/Leetcode/0042.trapping.rain.water.org @@ -6,9 +6,54 @@ right that's higher than that at position i. Now if we maintain a max height from both sides, and if they are both higher than position i, we know some water can be trapped at position i, the amount is the minimum of the max heights minus the height at i. - One pointer move from left to right starting at 0, while the other from right to left starting at n - 1. - We also keep track of max heights the two pointers have seen. + One pointer move from left to right starting at 0, while the other from right to left starting at n - 1. We also keep track of max heights the two pointers + have seen. - + Time Complexity: O(n), every height is accessed at most twice. + + #+begin_src C++ + int waterTrapped(vector& heights) { + int n = heights.size(); + int l = 0, r = n - 1; + int lmax = -1, rmax = -1; + int water = 0; + while (l < r) { + lmax = max(lmax, heights[l]); + rmax = max(rmax, heights[r]); + if (lmax < rmax) { + water += lmax - heights[l++]; + } else { + water += rmax - heights[r--]; + } + } + return water; + } + #+end_src +* Solution 2: min-stack + Using a stack to keep track of a decreasing sequence of heights, if the next height is higher than the top of the stack and the stack has more than one + element, then some water can be trapped in between current height and the one next to the top. How much? It's the number of heights between current and the + height next to the current. + + Time complexity: O(n) + Space complexity: O(n), there could be at most n elements in the stack. + + #+begin_src C++ + int trap(vector& heights) { + int n = heights.size(); + int water = 0; + stack stk; + for(int i = 0; i < n; ++i) { + int h = heights[i]; + while(!stk.empty() && heights[stk.top()] < h) { + int top = stk.top(); stk.pop(); + if (stk.empty()) break; + int blockHeight = min(heights[stk.top()], h) - heights[top]; + water += blockHeight * (i - stk.top() - 1); + } + stk.push(i); + } + return water; + } + #+end_src diff --git a/Algorithms/Leetcode/0115.distinct.subsequences.org b/Algorithms/Leetcode/0115.distinct.subsequences.org new file mode 100644 index 0000000..6f6c58d --- /dev/null +++ b/Algorithms/Leetcode/0115.distinct.subsequences.org @@ -0,0 +1,18 @@ +#+title: Distinct Subsequences + +Given two strings s and t, return the number of distinct subsequences of s which equals t. + +A string's subsequence is a new string formed from the original string by deleting some (can be none) of the characters without disturbing the remaining +characters' relative positions. (i.e., "ACE" is a subsequence of "ABCDE" while "AEC" is not). + +The test cases are generated so that the answer fits on a 32-bit signed integer. + +* Recursive call + memoization + + Let \(f(i, j)\) be the number of distinct subsequences of s[i:] that equal t[j:], now what does \(f\) look like? + + 1. if \(j = length(t)\), the value is 1, as we have reached the end of string t. + 2. if \(i = length(s)\), the value is 0, i.e. there's no more characters in s, but still some "unmatched" characters in t. + 3. if \(s[i] = t[j]\), the value is \(f(i + 1, j + 1) + f(i + 1, j)\), that is the number of distinct subsequences of s[i+1:] that equal t[j+1:], plus the + number of distinct subsequences of s[i+1:] that equal t[j:]. That is, we can skip both, or we can only skip one character in s. + 4. if \(s[i] != t[j]\), the value is \(f(i + 1, j)\), we cannot skip character in t, as we did not see a match. diff --git a/Algorithms/Leetcode/0128.longest.consecutive.sequence.org b/Algorithms/Leetcode/0128.longest.consecutive.sequence.org new file mode 100644 index 0000000..9074088 --- /dev/null +++ b/Algorithms/Leetcode/0128.longest.consecutive.sequence.org @@ -0,0 +1,9 @@ +#+title: Longest Consecutive Sequence + +Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence. + +You must write an algorithm that runs in O(n) time. + +* Solution: hash set + + If we keep a hashset that contains all elements from the input array, and we can test whether an element is in the set or not in roughly O(1) time. diff --git a/Algorithms/Leetcode/0302.smallest.rectangle.encloing.black.pixels.org b/Algorithms/Leetcode/0302.smallest.rectangle.encloing.black.pixels.org new file mode 100644 index 0000000..e2bf893 --- /dev/null +++ b/Algorithms/Leetcode/0302.smallest.rectangle.encloing.black.pixels.org @@ -0,0 +1,19 @@ +#+title: Smallest Rectangle Enclosing Black Pixels + +Given =mxn= binary matrix where =0= represents a white pixel and =1= a black pixel. Also given the location of one of the black pixels, =x= and =y= +find the area of the smallest rectangle that encloses all the black pxiels. + +Time complexity must be less than =O(mn)=. + +* Analysis + + To Calculate the area, we need four numbers: (left, top) - (right, bottom) + + - top: minimum of y + - bottom: maximum of y + - left: minimum of x + - right: maximum of x + + - =O(mn)= is easy: DFS/BFS, and update the four numbers along the way. + + - Is there a way to not go through all the nodes? diff --git a/Algorithms/Leetcode/0452.minimum.number.of.arrows.to.burst.balloons.html b/Algorithms/Leetcode/0452.minimum.number.of.arrows.to.burst.balloons.html new file mode 100644 index 0000000..dd97335 --- /dev/null +++ b/Algorithms/Leetcode/0452.minimum.number.of.arrows.to.burst.balloons.html @@ -0,0 +1,255 @@ + + + + + + + +Minimum Number of Arrows to Burst Balloons + + + + + +
+

Minimum Number of Arrows to Burst Balloons

+
+

Table of Contents

+ +
+

+Balloons are tape to a flat wall (X-Y plane). Balloons are represented as a range (xstart, xend). An arrow shot directly upward (x) can burst a balloon +iff. xstart <= x <= xend. +

+ +

+Return the minimum number of arrows needed to burst all balloons. +

+ +
+

1 Solution: sort and scan

+
+
    +
  1. An arrow can burst multiple balloons if they overlap. In the extreme case, two balloons can be burst if they are placed side-by-side with no gap between +them - according to the problem description.
  2. +
  3. The problem is now to count the number of overlaps that touch all the balloons.
  4. +
  5. Let's first consider the balloon with the smallest xend, how many balloons overlap with it?
  6. +
+
+
+
+
+

Created: 2022-03-06 Sun 17:24

+

Validate

+
+ + diff --git a/Algorithms/Leetcode/0452.minimum.number.of.arrows.to.burst.balloons.org b/Algorithms/Leetcode/0452.minimum.number.of.arrows.to.burst.balloons.org new file mode 100644 index 0000000..8ef62e3 --- /dev/null +++ b/Algorithms/Leetcode/0452.minimum.number.of.arrows.to.burst.balloons.org @@ -0,0 +1,17 @@ +#+title: Minimum Number of Arrows to Burst Balloons + +Balloons are tape to a flat wall (X-Y plane). Balloons are represented as a range (x_start, x_end). An arrow shot directly upward (x) can burst a balloon +iff. x_start <= x <= x_end. + +Return the minimum number of arrows needed to burst all balloons. + +* Solution: sort and scan + + 1. An arrow can burst multiple balloons if they overlap. In the extreme case, two balloons can be burst if they are placed side-by-side with no gap between + them - according to the problem description. + 2. The problem is now to find the number of non-overlapping balloons, and other balloons all overlap with at least one of them. + 3. Let's first consider the balloon with the smallest x_end, how many balloons overlap with it? The answer is all the balloons whose x_start is less than or + equal to it. In other words, the balloon whose x_start is greater than this x_end does not overlap with this baloon, and to burst them both, we need two + arrows. + 4. Now we need to consider this new baloon with a greater x_end, same problem with less remaining balloons. + diff --git a/Algorithms/Leetcode/0454.4sum.2.org b/Algorithms/Leetcode/0454.4sum.2.org new file mode 100644 index 0000000..10e2830 --- /dev/null +++ b/Algorithms/Leetcode/0454.4sum.2.org @@ -0,0 +1,6 @@ +#+title: 4Sum II + +* Solution: Hashmap + + Divide the arrays into two groups: (nums1, nums2) and (nums3, nums4). For the first group, calculate and save the (sum, number of (i, j)) mapping into a hashmap. + Then for each pair of numbers in the second group, find whether the negative of their sum is in the hashmap, if yes, add the value to the final answer. diff --git a/Algorithms/Leetcode/0740.delete.and.earn.html b/Algorithms/Leetcode/0740.delete.and.earn.html new file mode 100644 index 0000000..5362638 --- /dev/null +++ b/Algorithms/Leetcode/0740.delete.and.earn.html @@ -0,0 +1,289 @@ + + + + + + + +Delete and Earn + + + + + + + +
+

Delete and Earn

+
+

Table of Contents

+
+ +
+
+

+Given an integer array nums. Maximize the number of points by performing the following operations: +

+ +
    +
  • Pick a number nums[i] and delete it to earn nums[i] points. Afterwards, delete every element equal to nums[i]-1 and nums[i]+1.
  • +
+ +
+

1 Analysis

+
+

+If we have to delete all the numbers that's 1-distance from the picked number, we'd better pick all the occurances of this number. +

+ +

+For the maximum number nums[k], we can either: +

+
    +
  1. Use it and earns nums[k]*count[nums[k]] points, in this case, we cannot earn points for nums[k]-1 (we can still earn points for nums[i]-2);
  2. +
  3. Not use it and earns 0 point, but we can earn points for nums[k]-1, if it's better than not picking nums[k]-1, etc.
  4. +
+ +

+Now we can write down a recursive relationship for the maximum number in the array: +

+ +

+\(F(x)=max(x*count[x] + F(x-2), F(x-1)) if x is in the array, otherwise F(x) = F(x-1).\) +

+
+
+
+
+

Created: 2022-03-05 Sat 23:14

+

Validate

+
+ + diff --git a/Algorithms/Leetcode/0740.delete.and.earn.org b/Algorithms/Leetcode/0740.delete.and.earn.org new file mode 100644 index 0000000..000eda2 --- /dev/null +++ b/Algorithms/Leetcode/0740.delete.and.earn.org @@ -0,0 +1,51 @@ +#+title: Delete and Earn + +Given an integer array =nums=. Maximize the number of points by performing the following operations: + +- Pick a number =nums[i]= and delete it to earn =nums[i]= points. Afterwards, delete every element equal to =nums[i]-1= and =nums[i]+1=. + +* Analysis + + If we have to delete all the numbers that's 1-distance from the picked number, we'd better pick all the occurances of this number. + + For the maximum number =nums[k]=, we can either: + 1. Use it and earns =nums[k]*count[nums[k]]= points, in this case, we cannot earn points for =nums[k]-1= (we can still earn points for =nums[i]-2=); + 2. Not use it and earns =0= point, but we can earn points for =nums[k]-1=, if it's better than not picking =nums[k]-1=, etc. + + Now we can write down a recursive relationship for the maximum number in the array: + + 1. If x is in the array: + + \(F(x)=max(x*count[x] + F(x-2), F(x-1))\) + + 2. Otherwise + + \(F(x) = F(x-1)\) + +* Impl + + #+begin_src C++ + int deleteAndEarn(vector& nums) { + vector count(10001, 0); + for(int x : nums) ++count[x]; + + int use = 0, avoid = 0, prev = -1; + for (int i = 1; i <= 10000; ++i) { + if (count[i] > 0) { + int prevMax = max(use, avoid); + int curValue = i * count[i]; + if (i - 1 == prev) { + use = curValue + avoid; // if pick cur number i, must avoid prev number + } else { + use = curValue + prevMax; // If prev number is less than i - 1, we can pick current number AND prev number. + } + // Do not pick the current number, will get the maximum of prev number's use/avoid. + avoid = prevMax; + prev = i; + } + } + return max(use, avoid); + } + #+end_src + + diff --git a/Algorithms/Leetcode/1359.count.all.valid.pickup.and.delivery.options.org b/Algorithms/Leetcode/1359.count.all.valid.pickup.and.delivery.options.org new file mode 100644 index 0000000..a91edd7 --- /dev/null +++ b/Algorithms/Leetcode/1359.count.all.valid.pickup.and.delivery.options.org @@ -0,0 +1,33 @@ +#+title: Count All Valid Pickup and Delivery Options + +Given =n= orders, each order consist in pickup and delivery services. + +Count all valid pickup/delivery possible sequences such that delivery(i) is always after pickup(i). + +Return the answer modulo \(10^9+7\) + +* Constructing a valid option from the existing one + + Suppose we already have a valid pickup/delivery option for =n-1=, we want to calculate how many valid options if we add another order \(P_n, D_n\). + + In the =n-1= orders' arrangements, we have \(2n - 2\) elements (either Pickup or Delivery), there are \(2n - 2 + 1\) "slots" where we can place the new order's pickup service. + Once the pickup service is placed, suppose it's in position \(i\), where \(0<= i <=2n-2\), then the delivery service has \(2n-1-i\) options. The total options is: + + \(sum_{0<=i<=2n-2}(2n-1-i) = sum_{1<=i<=2n-1}(i) = frac^{(2n-1)*2n}_{2} = n * (2n - 1)\) + + Suppose the number of valid options for =n= orders is \(f(n)\), then: + + \(f(n) = n * (2n-1) * f(n-1)\) + + and \(f(1) = 1\) + + #+begin_src C++ + const static int M = static_cast(1e9 + 7); + int countOrders(int n) { + if (n == 1) return 1; + int multiplier = n * (2 * n - 1); + long long t = countOrders(n - 1); + return static_cast((t * multiplier) % M); + } + #+end_src + diff --git a/Algorithms/Leetcode/1606.find.servers.that.handled.most.number.of.requests.org b/Algorithms/Leetcode/1606.find.servers.that.handled.most.number.of.requests.org new file mode 100644 index 0000000..0e9a68f --- /dev/null +++ b/Algorithms/Leetcode/1606.find.servers.that.handled.most.number.of.requests.org @@ -0,0 +1,10 @@ +#+title: Find Servers That Handled Most Number of Requests + +* Note + + 1. Ordered set (RB-tree in C++) to keep track of available servers + 2. A priority queue that returns the assignment with least end time first, we pop and add the server back to the available set if the current job's start time + is not less than the top end time. + 3. To query the available server, find the first element in the set that's greater than or equal to =i%k= where =i= is the job index, if no such server is + found, e.g. all available server ids are less than =i%k=, use the smallest server id - wrapping around. + 4. *Don't forget to remove the assigned server from available set.* diff --git a/Algorithms/Leetcode/1756.design.most.recently.used.queue.org b/Algorithms/Leetcode/1756.design.most.recently.used.queue.org new file mode 100644 index 0000000..25af4b0 --- /dev/null +++ b/Algorithms/Leetcode/1756.design.most.recently.used.queue.org @@ -0,0 +1,58 @@ +#+title: Design Most Recently Used Queue + +Design a queue-like data structure that moves the most recently used element to the end of the queue. + +Implement the MRUQueue class: + +- =MRUQueue(int n)= constructs the MRUQueue with n elements: [1,2,3,...,n]. +- =int fetch(int k)= moves the kth element (1-indexed) to the end of the queue and returns it. + +* Approach + + - =fetch(int k)= involves two operations, 1) remove the k-th element 2) put it to the end of the queue + + Using an array offers O(1) access to any element, but O(n) to move element to the back of the queue. + + A linked list offers O(1) move to the back of the queue, but O(n) to locate the k-th element. + + We can sort of combine the two: linked list to keep all the elements, and a vector of iterators into different parts of the linked list, skipping multiple elements. + +#+begin_src C++ + class MRUQueue { + private: + using iterator = list::iterator; + const int step = 64; + int n; + list elements; + vector skips; // index: 0, 64, 128, ... + + public: + MRUQueue(int n) : n{n} { + for (int i = 1; i <= n; ++i) { + auto iter = elements.insert(elements.end(), i); + if (i % step == 1) { + skips.push_back(iter); + } + } + } + + int fetch(int k) { + --k; // convert to 0-based + int m = skips.size(); + // skip until k is less than step + int i = k / m; + auto iter = skips[i]; + advance(iter, k); + int v = *iter; + elements.push_back(v); + if (k == 0) { + skips[i]++; + } + while (++i < m) { + skips[i]++; + } + elements.erase(iter); + return v; + } + }; +#+end_src diff --git a/Algorithms/Leetcode/algorithms.for.problems.org b/Algorithms/Leetcode/algorithms.for.problems.org new file mode 100644 index 0000000..7a0e674 --- /dev/null +++ b/Algorithms/Leetcode/algorithms.for.problems.org @@ -0,0 +1,34 @@ +#+title: Algorithms for Problems + +* Binary Search + - 302. Smallest Rectangle Enclosing Black Pixels + 1. If we project the black pixels to the X- or Y-axis, we get a contiguous 1-D region, because all the black pixels are connected. + 2. Binary search on the for ranges to locate the boundaries. We know (x, y) is black + [0, x) for top + [x + 1, h) for bottom + [0, y) for left + [y + 1, w) for right +* Fast-slow pointers (Floyd's cycle detection) + - 141. Linked List Cycle + - 142. Linked List Cycle II + Return the node where the cycle begins. + Some definitions: + n: total number of nodes in the list + k: number of nodes before the cycle, 0 <= k <= n, when k == n, there's no cycle + c: number of nodes in the cycle: k + c = n + Now, when fast and slow meet, suppose slow moved x steps, and fast moved 2*x steps, and they met d steps from the cycle's starting point. + And we have: + + 1. x = k + d + + 2. 2*x = k + d + m * c + + 3. From 1. and 2.: k + d = m * c => k = m * c - d + + From 3, we know that if we start two pointers again, one from the head and one from the meeting point and move them one step at a time, they will meet at + the cycle starting pointer. Why? if we label the cycle starting pointer 0, and its next 1, ... and the last node in the cycle c-1. And suppose we start at + node d, and move k steps, or m * c - d steps, we land on the node d + m * c - d == 0 (mod c) + +* Two pointers (left, right) + - 1. Two Sum: Sort the array and use two pointers to search for the result. Moving the left pointer to right will increase the sum, while moving the right + pointer to left will decrease the sum. diff --git a/Books/c++.programming.lang.org b/Books/c++.programming.lang.org index b6e56e2..4c31b4e 100644 --- a/Books/c++.programming.lang.org +++ b/Books/c++.programming.lang.org @@ -282,3 +282,19 @@ - It's not possible to redefine an operator for a pair of built-in types, such as pointers. +* Ch8. Struct, unions and enumerations +** Structs +** Unions +** Enumerations + 1. =enum class= for which the enum names are local to the enum and do not implicitly convert to other values. + 2. "Plain enums" for which the enum names are in the same scope as the enum and implicitly converts to integers. +* Ch9. Statements + + - Declaration is a statement + - Expression becomes a statement with a ';' at its + - Statements do not have value, unlike expressions. + - + +* Ch10. Expressions + + diff --git a/Talks/Interview.Techniques/System.Design/System.Design.Introduction.org b/Talks/Interview.Techniques/System.Design/System.Design.Introduction.org new file mode 100644 index 0000000..1d7dc2a --- /dev/null +++ b/Talks/Interview.Techniques/System.Design/System.Design.Introduction.org @@ -0,0 +1,117 @@ +#+title: System Design Introduction for Interview + +* Basics + + - Ask good questions + - What features to work on (scope) very important. + - How much to scale. + - Don't use Buzzwords + - Backfires + - Clear and organized thinking + - Make sure to get the big picture right + - Drive discussion (80-20 rule) + - You should be talking 80% of the time + - Interviewer should talk 20% of the time + +* Things to consider + +** Features + + Define the behaviour of the system. What to include/exclude. + +** Define the APIs + API to implement the features. + Who, how to call the API. + +** Availablility + How much availability is required. e.g. what if a host went down or a data centre went down. + +** Latency performance + Response time is important for end user API/services. + +** Scalability + How does it scale for more users. + +** Durability + Data are durable, not lost or compromised. + +** Class Diagram + S.O.L.I.D. principles + +** Security & Privacy + For authentication services + +** Cost effective + Trade-offs + +* Concepts you need to know + - Veritcal (more memory/CPU) vs Horizontal scaling (more hosts) + - CAP theorm(!) only two out of three. + - Consistency: read always return most recent write + - Availability: every request receives a response, no guarantee it's the most recent + - Partition tolerance: system continues to operate despite an arbitrary number of messages dropped/delayed by the network between nodes. + - ACID vs BASE + - ACID: Atomic, Consistent, Isolated and Durable + - BASE: Basically available, soft state, Eventually consistent + - Partitioning/sharding data + - Split the data to multiple nodes + - *Consistent hashing* https://en.wikipedia.org/wiki/Consistent_hashing + - Optimistic vs Pessimistic Locking + - Strong vs Eventually consistency + - Relational DB vs NoSql + - Types of NoSql + - Key-value + - Wide-column + - Document based + - Graph based + - Caching + - Shared/not shared with different nodes + - Data center/Racks/hosts + - CPU/memory/harddrive/Network bandwidth + - Random vs Sequential read/write on disk + - HTTP vs HTTP/2 vs websockets + - TCP/IP model + - IPv4 vs IPv6 + - TCP vs UDP + - DNS lookup + - Https vs TLS + - Public key infrastructure & Certificate Authority + - Symmetric vs Asymmetric encryption + - Load Balancer - L4 vs L7 + - L7: authentication/smart routing/TLS termination + - CDNs and Edge + - Bloom filters & count-min sketch + - Paxos - consensus over distributed hosts + - Zookeeper, leader election + - Design patterns & object oriented design + - Virutal machines & containers + - Publisher-subscriber over queue + - Map-reduce + - multi-threading, concurrency, locks, synchronization, CAS + +* Tools + + - Cassandra - wide-column, scalable + - Consistent hashing + - MongoDB/Couchbase + - MySQL/PostgreSQL + - Relational database + - Redis + - key-value (data structures: hashmap, list, set, skip list...) + - Can be configured to take snapshot of data.` + - Memcached + - Zookeeper + - Centralized configuration management + - Leader election + - Distributed locking + - Scale well with reads, but not so good with writes + - Kafka + - Pub-sub queue + - Exactly once, messages ordered in one partition in one topic + - Nginx + - HAProxy + - Solr, Elastic Search (Full text search) + - Blob store, S3, GCS + - Docker + - K8s, container orchestration + - Hadoop/Spark