{"id":2696,"date":"2024-10-16T11:12:10","date_gmt":"2024-10-16T11:12:10","guid":{"rendered":"https:\/\/algocademy.com\/blog\/the-role-of-algorithms-in-problem-solving-a-comprehensive-guide\/"},"modified":"2026-10-15T09:07:30","modified_gmt":"2026-10-15T09:07:30","slug":"the-role-of-algorithms-in-problem-solving-a-comprehensive-guide","status":"publish","type":"post","link":"https:\/\/algocademy.com\/blog\/the-role-of-algorithms-in-problem-solving-a-comprehensive-guide\/","title":{"rendered":"The Role of Algorithms in Problem Solving, With Examples"},"content":{"rendered":"<p>An algorithm is a precise, finite sequence of steps that turns an input into the output you want. Its role in problem solving is to decide whether your solution works at the size of the real problem: two correct programs can differ by a factor of millions in running time, and the algorithm is what makes that difference. This guide shows that effect with one example, then covers the main families of algorithms and how to practice choosing between them.<\/p>\n<h2>What makes something an algorithm<\/h2>\n<p>A recipe is a loose algorithm. In computing, the definition is stricter:<\/p>\n<ul>\n<li>It has defined inputs and a defined output.<\/li>\n<li>Every step is unambiguous, so a machine can execute it.<\/li>\n<li>It finishes after a finite number of steps.<\/li>\n<li>It is correct: it gives the right output for every valid input, including edge cases such as an empty list.<\/li>\n<\/ul>\n<p>Note that &#8220;an algorithm&#8221; is not the same as &#8220;code&#8221;. The algorithm is the idea (for example, &#8220;keep a dictionary of the numbers I have seen&#8221;); the code is one way to write it down. Interviewers care about the idea first, which is why describing it before typing is a habit worth building.<\/p>\n<h2>One problem, two algorithms<\/h2>\n<p>Take the classic Two Sum problem: given a list of numbers and a target, return the indices of two numbers that add up to the target. The first idea most people have is to try every pair:<\/p>\n<pre><code class=\"language-python\">def two_sum_brute(nums, target):\n    for i in range(len(nums)):\n        for j in range(i + 1, len(nums)):\n            if nums[i] + nums[j] == target:\n                return [i, j]\n    return None<\/code><\/pre>\n<p>This is correct. It is also slow, because the number of pairs grows with the square of the input. Counting the inner-loop iterations for a list that never matches gives:<\/p>\n<table>\n<thead>\n<tr>\n<th scope=\"col\">List length<\/th>\n<th scope=\"col\">Pairs checked<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>1,000<\/td>\n<td>499,500<\/td>\n<\/tr>\n<tr>\n<td>2,000<\/td>\n<td>1,999,000<\/td>\n<\/tr>\n<tr>\n<td>4,000<\/td>\n<td>7,998,000<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Doubling the input quadruples the work. That is quadratic growth, written O(n\u00b2). Now ask a different question: for each number, what would its partner have to be? It is <code>target - number<\/code>, and a dictionary can tell us in constant time whether we have already seen it.<\/p>\n<pre><code class=\"language-python\">def two_sum_hash(nums, target):\n    seen = {}\n    for i, n in enumerate(nums):\n        if target - n in seen:\n            return [seen[target - n], i]\n        seen[n] = i\n    return None\n\nprint(two_sum_hash([2, 7, 11, 15], 9))  # [0, 1]\nprint(two_sum_hash([3, 3], 6))          # [0, 1]\nprint(two_sum_hash([1, 2], 10))         # None<\/code><\/pre>\n<p>This version looks at each element once, so the work grows in step with the input: O(n). It pays for that with extra memory, since the dictionary can hold up to n entries. Running both on a list of 20,000 numbers where the only matching pair sits at the very end, the pair-checking version needs about 200 million comparisons and is visibly slow, while the dictionary version finishes almost instantly.<\/p>\n<p>That trade, memory for time, is typical. The problem did not change; only the algorithm did. Learning algorithms is mostly learning a catalogue of such moves so you recognize when one applies. To practice the <a href=\"https:\/\/algocademy.com\/link\/?lang=py&amp;problem=two-sum&amp;solution=4\">hash table version of Two Sum<\/a>.<\/p>\n<h2>What algorithms give you<\/h2>\n<h3>Speed that holds as input grows<\/h3>\n<p>Small inputs hide bad algorithms. A quadratic solution feels instant on ten items and unusable on a million. Knowing the growth rate of your approach lets you predict this before you run anything, which is exactly what interviewers ask when they say &#8220;what is the time complexity?&#8221;<\/p>\n<h3>A way to break problems down<\/h3>\n<p>Most algorithm families are patterns for decomposing a problem: split it in half, solve a smaller version first, always take the best next item, or remember answers you have already computed. Once you know the patterns, an unfamiliar problem often turns out to be a familiar one in disguise.<\/p>\n<h3>Correctness you can argue for<\/h3>\n<p>An algorithm comes with reasoning: why it terminates, and why its answer is right. That reasoning is what lets you trust code on inputs you never tested.<\/p>\n<h2>The main families and when to reach for them<\/h2>\n<h3>Searching and binary search<\/h3>\n<p>If you must find an item in unsorted data, you have to look at everything: linear search, O(n). If the data is sorted, you can discard half of the remaining range with each comparison, so a list of a million items needs about 20 comparisons. Binary search is simple to describe and easy to get wrong at the boundaries, so it is worth writing carefully:<\/p>\n<pre><code class=\"language-python\">def binary_search(arr, x):\n    low, high = 0, len(arr) - 1\n    while low &lt;= high:\n        mid = (low + high) \/\/ 2\n        if arr[mid] &lt; x:\n            low = mid + 1\n        elif arr[mid] &gt; x:\n            high = mid - 1\n        else:\n            return mid\n    return -1\n\nprint(binary_search([2, 3, 4, 10, 40], 10))  # 3\nprint(binary_search([2, 3, 4, 10, 40], 5))   # -1<\/code><\/pre>\n<p>The same idea applies whenever a yes\/no question flips from &#8220;no&#8221; to &#8220;yes&#8221; at some point, not only to arrays. The <a href=\"https:\/\/algocademy.com\/link\/?lang=py&amp;problem=binary-search&amp;solution=1\">Binary Search lesson<\/a> walks through it step by step.<\/p>\n<h3>Graph search: DFS and BFS<\/h3>\n<p>Depth-first and breadth-first search explore graphs, grids and trees. Use BFS when you want the fewest steps from a start (shortest path in an unweighted graph) and DFS when you need to explore every possibility, for example when generating combinations or checking connectivity.<\/p>\n<h3>Sorting<\/h3>\n<p>Bubble, selection and insertion sort take O(n\u00b2) time in the worst case and are mostly teaching tools. Merge sort is O(n log n) in every case; quicksort is O(n log n) on average but O(n\u00b2) in the worst case. In practice you call your language&#8217;s built-in sort, which is a tuned O(n log n) algorithm, and use your knowledge of sorting to recognize when sorting first makes a problem easy (finding duplicates, merging intervals, two-pointer scans).<\/p>\n<h3>Divide and conquer<\/h3>\n<p>Split the problem into independent smaller pieces, solve each, and combine the results. Merge sort and binary search are the standard examples. The question to ask is whether the pieces really are independent; if they overlap, you want the next technique.<\/p>\n<h3>Dynamic programming and memoization<\/h3>\n<p>When a recursive solution solves the same subproblem repeatedly, store the answers. The Fibonacci numbers show the effect clearly. The naive recursion below makes 242,785 calls to compute <code>fib(25)<\/code>; with caching it computes each value once, 26 in total:<\/p>\n<pre><code class=\"language-python\">from functools import lru_cache\n\n@lru_cache(maxsize=None)\ndef fib(n):\n    return n if n &lt; 2 else fib(n - 1) + fib(n - 2)\n\nprint(fib(25))  # 75025<\/code><\/pre>\n<p>Dynamic programming is the same idea applied to harder problems, usually by defining the answer for a smaller input and building up. For the related choice between recursion and loops, there is a separate post on <a href=\"https:\/\/algocademy.com\/blog\/recursive-vs-iterative-algorithms-pros-and-cons\/\">recursive vs iterative algorithms<\/a>.<\/p>\n<h3>Greedy algorithms<\/h3>\n<p>A greedy algorithm takes the best-looking option at each step and never reconsiders. It is fast and simple, but only correct when the problem has the right structure, and that has to be argued, not assumed. Coin change is the standard warning. With US coins (1, 5, 10, 25), taking the largest coin first gives the minimum number of coins. With coins 1, 3 and 4 and an amount of 6, greedy picks 4 + 1 + 1 (three coins), while the best answer is 3 + 3 (two coins), which dynamic programming finds. Both claims are easy to confirm by running them, and the lesson is that &#8220;it worked on my examples&#8221; is not a proof.<\/p>\n<h2>A process for choosing the algorithm<\/h2>\n<ol>\n<li><strong>Write the simplest correct solution first.<\/strong> Brute force gives you a baseline and a way to check later versions.<\/li>\n<li><strong>Estimate its cost.<\/strong> Look at the input limits in the problem. A few thousand items tolerates O(n\u00b2); a million items does not.<\/li>\n<li><strong>Find the repeated work.<\/strong> Are you rescanning the same data, recomputing the same subproblem, or re-sorting? That repetition is where the speedup lives.<\/li>\n<li><strong>Match it to a pattern.<\/strong> Sorted input suggests binary search or two pointers; &#8220;have I seen this before?&#8221; suggests a hash set or map; overlapping subproblems suggest memoization; shortest path suggests BFS.<\/li>\n<li><strong>Test edge cases and trace by hand.<\/strong> Empty input, one element, duplicates, negative numbers. A <a href=\"https:\/\/algocademy.com\/blog\/how-to-dry-run-code-with-sample-test-cases-during-a-coding-interview\/\">dry run with sample test cases<\/a> catches most off-by-one errors.<\/li>\n<\/ol>\n<h2>Common mistakes<\/h2>\n<ul>\n<li><strong>Memorizing solutions instead of patterns.<\/strong> You will meet a variation you have not seen. Be able to say why the approach works.<\/li>\n<li><strong>Optimizing before you have a correct answer.<\/strong> A clever wrong solution scores worse than a plain right one.<\/li>\n<li><strong>Ignoring hidden costs.<\/strong> Slicing a list or concatenating strings inside a loop can quietly turn an O(n) idea into O(n\u00b2).<\/li>\n<li><strong>Trusting greedy without checking.<\/strong> Try to build a counterexample before you commit.<\/li>\n<li><strong>Forgetting memory.<\/strong> Hash maps and memoization trade space for time; mention that trade-off out loud in interviews.<\/li>\n<\/ul>\n<h2>Practicing so it sticks<\/h2>\n<p>Algorithmic skill comes from solving problems, then reflecting on them. Solve one, then ask what the brute force was, what made the better version faster, and which pattern it belongs to. Group problems by pattern (binary search, two pointers, hash maps, recursion) rather than doing them in random order, and revisit ones you got wrong after a few days. Explain your approach aloud as you go, since interviews test communication as much as the final code. Platforms such as LeetCode and HackerRank offer large problem banks; <a href=\"https:\/\/app.algocademy.com\/\">AlgoCademy<\/a> is built around short lessons with step-by-step guidance if you prefer to learn each pattern before facing interview-style problems.<\/p>\n<h2>FAQ<\/h2>\n<h3>Do I need advanced math to learn algorithms?<\/h3>\n<p>No. Comfort with loops, arrays, recursion and basic logarithms (how many times you can halve a number) covers most interview material.<\/p>\n<h3>Which algorithms matter most for interviews?<\/h3>\n<p>Hash maps, sorting and two pointers, binary search, BFS\/DFS, recursion with memoization, and basic dynamic programming cover the large majority of questions. Rarely used topics can wait.<\/p>\n<h3>Is it still worth learning algorithms when libraries and AI tools write code?<\/h3>\n<p>Yes. Tools can produce code, but you still have to judge whether it is correct and whether it will hold up at your data size, and that judgment is algorithmic thinking. Interview loops at many companies still test it directly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What algorithms do in problem solving: how the right one turns an unusable program into a fast one, the main families, and how to practice for interviews.<\/p>\n","protected":false},"author":1,"featured_media":2695,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23],"tags":[],"class_list":["post-2696","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-problem-solving"],"_links":{"self":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/2696"}],"collection":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/comments?post=2696"}],"version-history":[{"count":1,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/2696\/revisions"}],"predecessor-version":[{"id":8673,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/2696\/revisions\/8673"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/media\/2695"}],"wp:attachment":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/media?parent=2696"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/categories?post=2696"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/tags?post=2696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}