Learn Trapping Rain Water, Top K Frequent and Selection Sort with Step-by-Step Visualization in DSA View View ππ
Hoi hoi! Iβm @nyaomaru, a frontend engineer who has been obsessed with ramen lately. πΈπ Have you used DSA View View already? ππ I Built a Tool to Visualize DSA. Letβs Learn Together! (DSA View View ππ) Features a timeline to step backward mid-loop nyaomaru nyaomaru nyaomaru Follow Jul 15 I Built a Tool to Visualize DSA. Letβs Learn Together! (DSA View View ππ) #showdev #typescript #dsa #react 64Β reactions 33Β comments 7 min read DSA View View allows you to understand DSA by visualizing how your implementation actually runs. In the previous articles, we looked at problems like: Two Sum Binary Search Bubble Sort Valid Parentheses Reverse Linked List Maximum Depth of Binary Tree Number of Islands Invert Binary Tree Course Schedule Is Learning DSA Boring? Let's Use DSA View View ππ (Two Sum, Binary Search, and Bubble Sort) Visualizing execution logic changes mental models nyaomaru nyaomaru nyaomaru Follow Aug 19 Is Learning DSA Boring? Let's Use DSA View View ππ (Two Sum, Binary Search, and Bubble Sort) #dsa #typescript #opensource #learning 51Β reactions 9Β comments 7 min read Learn Valid Parentheses, Reverse Linked List, and Tree Max Depth with Step-by-Step Visualization in DSA View View ππ Curated progression from stacks to recursion nyaomaru nyaomaru nyaomaru Follow Aug 26 Learn Valid Parentheses, Reverse Linked List, and Tree Max Depth with Step-by-Step Visualization in DSA View View ππ #typescript #algorithms #opensource #dsa 77Β reactions 5Β comments 9 min read Learn Number of Islands, Invert Binary Tree, and Course Schedule with Step-by-Step Visualization in DSA View View ππ Readers praise the recursive swap explanation nyaomaru nyaomaru nyaomaru Follow Sep 2 Learn Number of Islands, Invert Binary Tree, and Course Schedule with Step-by-Step Visualization in DSA View View ππ #typescript #dsa #opensource #webdev 64Β reactions 13Β comments 12 min read This time, let's try three more problems: Trapping Rain Water Top K Frequent Elements Selection Sort These three problems introduce some very useful ways of thinking Shrink a problem from both sides Count first, then organize by frequency Repeatedly select the next value Once again, the implementations are not necessarily huge. But there are several changing values that we need to keep in our heads. So instead of only reading the final code, Let's view what actually happens. ππ π§οΈ Trapping Rain Water Let's start with Trapping Rain Water. Suppose we have these heights [0, 1, 0, 2, 1, 0, 1, 3] If we draw them as walls, it looks roughly like this. β β β β β β β β ----------------- 0 1 0 2 1 0 1 3 Rain falls from above. Some water escapes. But some water becomes trapped between taller walls. For example β~~~~~~~β β~~~β~~~~~~~β ----------------- So the question is How much water can be trapped? At first, I found this problem quite confusing. πΏ Because the amount of water above one position depends on walls somewhere else. So what information do we actually need? How Much Water Fits Above One Position? Imagine this position left wall right wall β β β x β β β β The water level cannot be higher than the shorter side. So the maximum possible water level is Math.min(leftMax, rightMax); Then we subtract the current height. Conceptually: water = min(leftMax, rightMax) - currentHeight That's the basic idea. But do we really need to calculate both sides again for every position? No. We can use two pointers. Two Pointers Here is the implementation. function trap(height: number[]): number { let left = 0; let right = height.length - 1; let leftMax = 0; let rightMax = 0; let water = 0; while (left = rightMax) { rightMax = height[right]; } else { water += rightMax - height[right]; } right--; } } return water; } There are several important values. left right leftMax rightMax water This is exactly the kind of code where I understand every variable individually, but then lose track of all of them together. πΉ Let's follow a smaller example. [2, 0, 1, 3] Start From Both Ends At first left = 0 right = 3 [2, 0, 1, 3] β β left right The heights are: height[left] = 2 height[right] = 3 Since 2 []); for (const [num, count] of frequency) { buckets[count].push(num); } const result: number[] = []; for (let count = buckets.length - 1; count >= 0; count--) { for (const num of buckets[count]) { result.push(num); if (result.length === k) { return result; } } } return result; } Let's follow it. Step 1: Build the Frequency Map Start frequency = {} Read the first 1. And another one and another... 1 β 1 1 β 2 1 β 3 Then 2. And another one. 1 β 3 2 β 1 2 β 2 Finally 3. 1 β 3 2 β 2 3 β 1 Done. Step 2: Put Values Into Buckets Now buckets[count].push(num); For 1 β 3 we do buckets[3].push(1) For 2 β 2 we do buckets[2].push(2) And 3 β 1 becomes buckets[1].push(3) So 0: [] 1: [3] 2: [2] 3: [1] Step 3: Read From Highest Frequency We want the most frequent values. So don't start at 0. Start from the end. 3 β [1] 2 β [2] 1 β [3] Take 1. result = [1] We still need one more. Move down. Take 2. result = [1, 2] Now result.length === k So return. Done! π Why Is This Interesting? I like this solution because the second structure changes our perspective. The Map says value β frequency The buckets say frequency β values Same information. But different direction. And suddenly finding the most frequent values becomes easy. We just walk backward through the buckets. Complexity We count every number once. We distribute every unique number into a bucket. Then we walk through the buckets. Time: O(n) Space: O(n) π Let's View View It There are two transformations happening here. First nums β frequency Map Then frequency Map β buckets Then buckets β result Reading the final implementation, it can be easy to miss why we're building two different data structures. dsa-view-view.vercel.app With the runtime visible, we can follow the data changing shape. [1, 1, 1, 2, 2, 3] β count 1 β 3 2 β 2 3 β 1 β bucket 1: [3] 2: [2] 3: [1] β highest first [1, 2] That's the part I like. We don't magically find the top K. We reorganize the information until the answer becomes easy to read. π’πΈ π Selection Sort Finally, let's sort something again! We already looked at Bubble Sort in a previous article. This time, let's try Selection Sort. Suppose we have [5, 3, 4, 1, 2] We want [1, 2, 3, 4, 5] Selection Sort follows a very simple idea Find the smallest remaining value and move it to the front. Then repeat. First Pass Start [5, 3, 4, 1, 2] β i Assume the first value is currently the smallest. minIndex = 0 Then scan everything to the right. 5 vs 3 3 is smaller. So: minIndex = 1 Then: 3 vs 4 No change. Then 3 vs 1 1 is smaller. minIndex = 3 Finally 1 vs 2 Still 1. So the smallest value is at index 3. Swap [5, 3, 4, 1, 2] β β i min β [1, 3, 4, 5, 2] Now the first position is finished. [1 | 3, 4, 5, 2] β sorted Repeat Next, start from index 1. [1 | 3, 4, 5, 2] β i Find the smallest value in [3, 4, 5, 2] That's 2. Swap. [1, 2 | 4, 5, 3] Again. Find the smallest remaining value. 3 Eventually [1, 2, 3, 4, 5] Sorted! π Implementation function selectionSort(nums: number[]): number[] { for (let i = 0; i < nums.length - 1; i++) { let minIndex = i; for (let j = i + 1; j < nums.length; j++) { if (nums[j] < nums[minIndex]) { minIndex = j; } } if (minIndex !== i) { [nums[i], nums[minIndex]] = [nums[minIndex], nums[i]]; } } return nums; } There are two important indexes. i minIndex And also j which searches through the unsorted area. Why Is It Called Selection Sort? Because each pass selects the smallest remaining value. Find smallest β Select it β Move it to the front β Repeat That's basically the whole algorithm. Complexity For every position, we search through the remaining values. So Time: O(nΒ²) We sort the array in place. Space: O(1) Selection Sort is not something I would normally choose for sorting a huge production dataset. πΉ But as a learning algorithm, it is wonderfully visual. π Let's View View It The implementation contains nested loops. for (let i = 0; i < nums.length - 1; i++) { let minIndex = i; for (let j = i + 1; j < nums.length; j++) { Reading it, I might lose track of: Which area is already sorted? Where is i? Where is j? What does minIndex currently point to? When exactly does the swap happen? dsa-view-view.vercel.app When we visualize it, the basic pattern becomes obvious. [5, 3, 4, 1, 2] β smallest [1 | 3, 4, 5, 2] β smallest [1, 2 | 4, 5, 3] The algorithm is continuously growing a finished area from left to right. That's Selection Sort. Pick the smallest remaining value. Put it next. And repeat. π₯πΈ π§ What Did We Actually Learn? Again, these three problems look completely different. But each one introduces a useful way of thinking. Trapping Rain Water Use information from both sides to decide which part can already be solved safely. Which side do I know enough about right now? Top K Frequent Elements Sometimes counting the data is only the first step. Reorganize it into a structure where the answer becomes easy to retrieve. Can I reorganize this information around what I actually need? Selection Sort Build the answer one permanent position at a time. What value belongs in this position next? So this time we saw Two pointers Frequency buckets Selection Three different mental models again. And just like the previous problems, the difficult part is often not the syntax. It's the changing state. Which pointer moved? What is the maximum now? What is inside the Map? Which bucket changed? Where is minIndex? Which part is already finished? That's a lot to keep in our heads. So instead, I want to view it. ππ π― Conclusion In this article, we looked at: Trapping Rain Water with two pointers Top K Frequent Elements with frequency buckets Selection Sort And more importantly, we followed how their state changes while they run. For Trapping Rain Water, we watched two pointers move inward while leftMax, rightMax, and water changed. left β β right For Top K Frequent Elements, we watched the same data change representation. array β frequency Map β buckets β result For Selection Sort, we watched the sorted area grow one position at a time. This is exactly the kind of thing I built DSA View View for. dsa-view-view.vercel.app You can write or load a TypeScript implementation, run it with your own inputs, and move backward and forward through the runtime. If you are learning DSA too, try viewing one of these problems step by step. And if there is a DSA problem you want me to cover next, please let me know in the comments! I still have many algorithms to learn myself. πΈ Let's train our DSA muscles together! πͺ If you like DSA View View, please give it a star β nyaomaru / dsa-view-view DSA View View allows you to understand DSA to see the data flow. ππ Of course, it's free. DSA View View DSA View View turns TypeScript algorithm functions into step-by-step visual stories. ππ Write code, run it with structured inputs, and see the arrays, matrices trees, lists, stacks, pointers, and return values move as the function executes. It is built for those moments when reading the code is not enough and you want to view why the answer changes. Why Try It? π§ Step through real TypeScript Paste or edit a function, validate it, then run the exact code in the browser. π§© Views that match the data Arrays become bars, matrices become grids, trees become node graphs, linked lists become chains, and two-pointer area problems get their own visual view. π³ DSA-friendly inputs out of the box TreeNode, ListNode, MinHeap, MaxHeap, PriorityQueue, nested arrays matrices, strings, numbers, and class-style inputs are supported without ceremony. π 39 built-in examples Search by name, browseβ¦ View on GitHub See you in the next article!
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to