🎄 Advent of Code 2025 – Day 11 Complete Wrapped up Day 11 of Advent of Code. This one was an elegant demonstration of how memoization transforms exponential problems into tractable ones. 𝗧𝗵𝗲 𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲 The input describes a directed graph where each node points to its children, ultimately leading to an 'out' node. 𝗣𝗮𝗿𝘁 1: Count all possible paths from a starting node ('you') to the destination ('out'). 𝗣𝗮𝗿𝘁 2: Count only the paths that pass through specific required nodes ('dac' AND 'fft') before reaching the destination. 𝗪𝗵𝗮𝘁 𝗠𝗮𝗱𝗲 𝗜𝘁 𝗜𝗻𝘁𝗲𝗿𝗲𝘀𝘁𝗶𝗻𝗴 Part 1 is a classic recursive path counting problem. The naive approach recalculates the same subproblems repeatedly, leading to exponential time complexity. Adding @cache (memoization) transforms it into a dynamic programming solution that computes each node's result exactly once. Part 2 adds a twist: constraint tracking. We need to count only paths that satisfy certain conditions. The solution tracks which required nodes have been visited using a frozenset as part of the state space. This allows us to maintain memoization while ensuring we only count valid paths. The key insight: state space design matters. By using (node, visited_required_nodes) as our state, we keep the cache size manageable at O(nodes × 2^k) where k is the number of required nodes. 𝗞𝗲𝘆 𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆𝘀: • Memoization: exponential → polynomial time complexity • State space design is crucial for efficient DP • Python's @cache decorator makes memoization trivial • Adding constraints requires careful state tracking • Frozensets enable hashable collections for caching 𝗣𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲 𝗜𝗺𝗽𝗮𝗰𝘁: Without memoization: Would timeout on large graphs With memoization: Instant results ⚡ This problem perfectly illustrates why dynamic programming is one of the most powerful optimization techniques in computer science. 🔗 Code Repository: https://lnkd.in/eYRvn-mk #AdventOfCode #DynamicProgramming #Algorithms #GraphTheory #Python #Memoization #ComputationalThinking #SoftwareEngineering #ProblemSolving
Advent of Code 2025 Day 11: Memoization Transforms Exponential Problems
More Relevant Posts
-
🎄 Advent of Code 2025 – Day 10 Complete Wrapped up Day 10 of Advent of Code. This one was a fascinating journey from brute force to constraint solving, teaching an important lesson about recognizing problem patterns. 𝗧𝗵𝗲 𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲 The input describes machines with buttons that toggle lights and reduce joltage values. 𝗣𝗮𝗿𝘁 1: Find the minimum button presses to toggle specific lights from off to a target pattern using XOR operations. 𝗣𝗮𝗿𝘁 2: Find the minimum button presses to reduce all joltage values from their initial state to zero, where each button press decrements specific positions. 𝗪𝗵𝗮𝘁 𝗠𝗮𝗱𝗲 𝗜𝘁 𝗜𝗻𝘁𝗲𝗿𝗲𝘀𝘁𝗶𝗻𝗴 Part 1 is a bitwise XOR problem solvable through combinatorial brute force. Each button toggles specific bit positions, and we need to find which combination produces the target state. Part 2 initially looked like a search problem, but attempting BFS/DFS leads to exponential state explosion and impossibly long runtimes. The key insight: Part 2 is actually a linear programming problem! Each button press creates a linear equation, and we need to minimize the sum of button presses while satisfying all constraints. This transforms an intractable search problem into one solvable instantly using the z3 constraint solver. This problem perfectly demonstrates how the same surface-level problem can require completely different algorithmic approaches. Recognizing whether you're dealing with search, optimization, or constraint satisfaction can make the difference between a solution that runs in milliseconds versus one that never finishes. 𝗞𝗲𝘆 𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆𝘀: Not every optimization problem requires exhaustive search Linear constraints → constraint solver (z3, OR-tools) Problem recognition is as important as implementation Sometimes the right tool makes the impossible trivial 🔗 Code Repository: https://lnkd.in/eT6542Ts #AdventOfCode #ProblemSolving #Algorithms #ConstraintSolving #Python #ComputationalThinking #SoftwareEngineering #Z3Solver
To view or add a comment, sign in
-
-
🌟 Day 40 of my 100 Days LeetCode Challenge 📘 Problem: LeetCode 1143 – Longest Common Subsequence 🧩 Difficulty: Medium 📚 Concepts: Dynamic Programming, String DP, Optimization 💡 Problem Summary You’re given two strings text1 and text2. A subsequence is formed by deleting some characters (or none) without changing the order of the remaining characters. 👉 The task is to find the length of the longest subsequence common to both strings. If no common subsequence exists, return 0. ✅ Approach & Thought Process This is a classic Dynamic Programming problem. Key ideas: Compare characters from both strings one by one. If characters match, they can extend a common subsequence. If they don’t match, skip one character from either string and take the best possible result. To optimize: Instead of using a full 2D table, we can keep only two rows at a time. This reduces space usage while preserving correctness. The solution builds answers incrementally, reusing results from smaller subproblems. ⏱ Complexity Time: O(n × m), where n and m are the lengths of the two strings Space: O(min(n, m)) using rolling DP optimization Efficient enough for large inputs. ✨ Key Takeaways LCS is a foundational DP problem—mastering it helps with many string problems. Subsequence ≠ Substring (order matters, continuity doesn’t). Space optimization is often possible once the DP transition is clear. Appears frequently in interviews, competitive programming, and bioinformatics. Onward to Day 41 🚀 #Python #LeetCode #100DaysOfCode #DynamicProgramming #Strings #ProblemSolving
To view or add a comment, sign in
-
-
🚀 LeetCode + DSA — Day 18 Today I solved the classic array problem “Remove Element”, which focuses on in-place array modification and pointer-based traversal. 🔹 Problem Overview Given an array of integers and a value val, the task is to remove all occurrences of val in-place and return the count of remaining elements. The relative order of elements can be changed, and no extra space should be used. 🔹 Approach Used ✔ Used a pointer to track the position for valid elements ✔ Traversed the array once ✔ Copied non-val elements forward ✔ Returned the final count of valid elements 🔹 Why This Works In-place modification avoids extra memory usage Single-pass traversal ensures optimal performance Pointer technique keeps the logic clean and efficient 📊 Performance ✅ All test cases passed (116/116) ⚡ Runtime: 0 ms (Beats 100%) 💾 Memory: Beats ~94% 💡 Key Takeaway In-place algorithms are essential for writing memory-efficient code. Simple pointer logic can often replace complex data structures when constraints are clear. Consistency over intensity — sharpening fundamentals one problem at a time 💪 #LeetCode #DSA #Python #Arrays #InPlaceAlgorithm #TwoPointers #CodingPractice #ProblemSolving #DailyCoding #TechGrowth #LearningJourney
To view or add a comment, sign in
-
-
🗓 Day 60 / 100 – #100DaysOfLeetCode 📌 Problem 1411: Number of Ways to Paint N × 3 Grid Today’s problem was a really good exercise in dynamic programming and pattern observation. The goal was to count the number of valid ways to paint an n × 3 grid using three colors, such that no two adjacent cells (horizontal or vertical) share the same color. 🧠 My Approach: Instead of tracking every possible coloring explicitly, I categorized each row into two patterns: 1️⃣ same – Rows where the 1st and 3rd cells have the same color (e.g., A B A) 2️⃣ diff – Rows where all three cells have different colors (e.g., A B C) For the first row: same = 6 diff = 6 Then for each subsequent row: A same pattern can be formed from: previous same rows in 3 ways previous diff rows in 2 ways A diff pattern can be formed from: previous same rows in 2 ways previous diff rows in 2 ways Using these transitions, I iterated row by row and applied modulo 10^9 + 7 to handle large values efficiently. 💡 Key Learning: This problem reinforced: ✔ breaking complex constraints into manageable states ✔ recognizing repeating patterns to optimize DP solutions ✔ reducing a large state space into just a few variables ✔ how mathematical transitions can drastically simplify implementation A perfect example of how thinking in patterns turns a hard-looking problem into a clean and elegant solution 🚀 #100DaysOfLeetCode #LeetCodeChallenge #Python #ProblemSolving #DynamicProgramming #DP #Combinatorics #Algorithms #DSA #CompetitiveProgramming #SoftwareEngineering #CodingJourney #DeveloperJourney #LearningInPublic #TechStudent #CareerGrowth #Programming #KeepLearning
To view or add a comment, sign in
-
-
🚀 Day 53 of #100DaysOfCode — Making Array Sum Divisible by K Hey everyone! 👋 Today’s challenge focused on a smart math-based optimization problem where the goal was to make the sum of an array divisible by a given number k using the minimum number of operations. 👨💻 What I practiced today: ✅ Understanding modulo (%) operations deeply ✅ Translating a problem into a simple mathematical observation ✅ Optimizing brute-force thinking into an O(n) solution ✅ Writing clean and minimal Python code 📌 Today’s Task: ✔ Given an integer array nums and an integer k ✔ In one operation, decrement any element by 1 ✔ Find the minimum operations required so that sum(nums) is divisible by k 🧠 Key Insight: If the sum of the array is S, then the minimum number of operations required is simply: S % k Because each operation reduces the sum by 1. 💡 Example: Input: nums = [3, 9, 7], k = 5 Sum = 19 → 19 % 5 = 4 Output: 4 ✨ Key Takeaway: Sometimes the best solution isn’t complex logic or loops — it’s recognizing a simple mathematical pattern. Mastering such observations can drastically reduce code complexity and runtime. #100DaysOfCode #Day53 #Python #LeetCode #ProblemSolving #MathInProgramming #CodingJourney #DSA #CleanCode
To view or add a comment, sign in
-
-
🗓 Day 59 / 100 – #100DaysOfLeetCode 📌 Problem 961: N-Repeated Element in Size 2N Array Today’s problem focused on identifying a repeating pattern in an array with well-defined constraints. The task was to find the element that appears n times in an array of size 2n, where all other elements are unique. 🧠 My Approach: I used a set-based approach to track elements as I traversed the array: Iterated through each element in the array. Stored visited elements in a set. If an element was already present in the set, that meant it was the repeated element → returned it immediately. This works efficiently because the problem guarantees exactly one element is repeated n times. 💡 Why this works well: Sets provide O(1) average time complexity for lookup. The repeated element is guaranteed to appear early due to frequency, so we can exit early. Simple logic with clean and readable code. 💡 Key Learning: This problem reinforced: ✔ how problem constraints can simplify the solution ✔ effective use of hash-based data structures ✔ recognizing patterns instead of overcomplicating logic ✔ writing efficient solutions even for “easy” problems A great example of how understanding constraints leads to elegant solutions 🚀 #100DaysOfLeetCode #LeetCodeChallenge #Python #ProblemSolving #Arrays #HashSet #Simulation #Algorithms #DSA #CompetitiveProgramming #SoftwareEngineering #CodingJourney #DeveloperJourney #LearningInPublic #TechStudent #CareerGrowth #Programming #KeepLearning
To view or add a comment, sign in
-
-
#rust #molar A big milestone for MolAR! The first molecular modeling library written in #Rust reached the version 1.0! It is now 100% safe and sound Rust with much more straightforward "rusty" API, which is much easier to reason about in comparison with the first rather convoluted prototype. The Python bindings remained the same with its own "pythonic" syntax and safer, more idiomatic internals. Try it out: GitHub: https://lnkd.in/dimWEGpF crates.io: https://lnkd.in/dfu6-9N8
To view or add a comment, sign in
-
Today’s challenge was LeetCode 1926: 𝘕𝘦𝘢𝘳𝘦𝘴𝘵 𝘌𝘹𝘪𝘵 𝘧𝘳𝘰𝘮 𝘌𝘯𝘵𝘳𝘢𝘯𝘤𝘦 𝘪𝘯 𝘔𝘢𝘻𝘦. On paper, it’s a textbook Breadth-First Search (BFS) problem—finding the shortest path in an unweighted grid. In practice, it was a great lesson on why implementation details matter just as much as algorithm choice. I chose BFS using a queue because we need the nearest exit, layer by layer. Each state in the queue tracked coordinates and the current distance from the start. My first few submissions were a mix of syntax errors and logic bugs: • 𝗜𝗻𝗱𝗲𝘅𝗶𝗻𝗴: I momentarily forgot I wasn't in NumPy and tried tuple-style indexing (`maze[r, c]`) instead of standard list indexing (`maze[r][c]`). • 𝗗𝗶𝘀𝘁𝗮𝗻𝗰𝗲 𝗧𝗿𝗮𝗰𝗸𝗶𝗻𝗴: I initially used a single global step counter. I quickly realized this counted 𝘯𝘰𝘥𝘦𝘴 𝘷𝘪𝘴𝘪𝘵𝘦𝘥 rather than 𝘥𝘪𝘴𝘵𝘢𝘯𝘤𝘦 𝘭𝘢𝘺𝘦𝘳𝘴, so I switched to storing the specific distance with each node in the queue. The real learning moment happened when my code hit a TLE. The logic was correct, but it was too slow. I realized I was marking cells as "visited" only after popping them from the queue. This meant that if multiple paths reached a neighbor before it was processed, that neighbor got added to the queue multiple times. I shifted the "visited" check to happen immediately upon 𝘦𝘯𝘲𝘶𝘦𝘶𝘦𝘪𝘯𝘨. I also modified the input grid directly (turning `.` to `+`) to mark visited spots. While this trades input immutability for speed, it eliminated duplicate work and cleared the time limit easily. It’s a small change in code placement, but a huge difference in runtime complexity. #LeetCode #CodingInterview #Python #BFS #Algorithms #JobSearch
To view or add a comment, sign in
-
-
LeetCode 2161: Partition array according to given pivot ➗ Topic: Simulation Imagine you want to rearrange an array so all numbers smaller than a given pivot come first, followed by all equals to the pivot, then all larger numbers—while preserving the original order within each group. How does the code work? - Initialization: ---- Create three empty lists: before for numbers < pivot, middle for numbers == pivot, and after for numbers > pivot. - Partitioning Loop: ---- Iterate through each number in the input nums array exactly once. ---- If num < pivot, append it to before. ---- If num == pivot, append it to middle. ---- Otherwise (num > pivot), append it to after. - Result Construction: ---- Concatenate the three lists in order: before + middle + after using - Python's list addition. ---- Return the new partitioned list (same length as input). Complexity: - Time Complexity: O(n) — single pass through n elements, each append is O(1) amortized, concatenation is O(n). - Space Complexity: O(n) — three lists store all n elements plus temporary result list. Check out the problem here: https://lnkd.in/gu5yPWb9 Keep going, keep revising, and keep building confidence! 💪🔥 #DSA #Coding #ProblemSolving #Learning
To view or add a comment, sign in
-
More from this author
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development