<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Antesh Sharma on Medium]]></title>
        <description><![CDATA[Stories by Antesh Sharma on Medium]]></description>
        <link>https://medium.com/@coffee_addiction?source=rss-3ab1bab6c30f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*oMoGeYAacRHq0HhdoEW9Dw.jpeg</url>
            <title>Stories by Antesh Sharma on Medium</title>
            <link>https://medium.com/@coffee_addiction?source=rss-3ab1bab6c30f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 06:39:14 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@coffee_addiction/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Becoming a Single Parent Overnight]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/@coffee_addiction/becoming-a-single-parent-overnight-c2f12b251469?source=rss-3ab1bab6c30f------2"><img src="https://cdn-images-1.medium.com/max/1170/1*eeyG728nENdGrrmBD2JttQ@2x.jpeg" width="1170"></a></p><p class="medium-feed-link"><a href="https://medium.com/@coffee_addiction/becoming-a-single-parent-overnight-c2f12b251469?source=rss-3ab1bab6c30f------2">Continue reading on Medium »</a></p></div>]]></description>
            <link>https://medium.com/@coffee_addiction/becoming-a-single-parent-overnight-c2f12b251469?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/c2f12b251469</guid>
            <category><![CDATA[personal-growth]]></category>
            <category><![CDATA[self-improvement]]></category>
            <category><![CDATA[parenting]]></category>
            <category><![CDATA[children]]></category>
            <category><![CDATA[parents]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Fri, 03 Apr 2026 04:54:16 GMT</pubDate>
            <atom:updated>2026-04-03T04:54:16.851Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[Let’s talk about Coding Basics for young engineers]]></title>
            <link>https://medium.com/@coffee_addiction/lets-talk-about-coding-basics-for-young-engineers-6da11bf7c3fc?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/6da11bf7c3fc</guid>
            <category><![CDATA[python]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Fri, 18 Apr 2025 12:50:54 GMT</pubDate>
            <atom:updated>2025-04-19T03:31:26.774Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/194/1*3pG1FLgObFciG6vKeE0XEg@2x.jpeg" /></figure><p>The journey into software engineering is both exciting and challenging. For young developers just stepping into the world of coding, having a solid foundation is more important than mastering every new language or framework. The fundamentals you build early in your career will shape your problem-solving ability, code quality, and overall growth as an engineer.</p><p>Starting a career in software development can feel overwhelming – new languages to learn, tools to master, and expectations to meet. But just like building a house, a lasting career begins with a solid foundation. The early habits you build, the principles you embrace, and the mindset you cultivate will shape your trajectory for years to come. This EBook lays the groundwork for a strong, resilient, and fulfilling career in software engineering.</p><p><strong>You can buy this book from here: </strong><a href="https://antesh6.gumroad.com/l/ourkj"><strong>h</strong>ttps://antesh6.gumroad.com/l/ourkj</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6da11bf7c3fc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Find the longest common prefix string amongst an array of strings]]></title>
            <link>https://medium.com/@coffee_addiction/find-the-longest-common-prefix-string-amongst-an-array-of-strings-78a446489fec?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/78a446489fec</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Mon, 25 Mar 2024 14:59:41 GMT</pubDate>
            <atom:updated>2025-04-19T03:37:00.965Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LtCaFFWyVUTQ8F2g0eQyQQ.jpeg" /><figcaption><em>Find the longest common prefix among an array of strings</em></figcaption></figure><p><strong>Buy book:</strong> Let’s talk about <strong>Coding Basics</strong> for young engineers <a href="https://antesh6.gumroad.com/l/ourkj">https://antesh6.gumroad.com/l/ourkj</a></p><p><em>To find the longest common prefix among an array of strings, we can optimize the approach to reduce unnecessary comparisons and improve efficiency.</em></p><blockquote><em># Example usage:</em></blockquote><blockquote><em>strs = [“flower”, “flow”, “flight”]</em></blockquote><blockquote><em>Output: “fl”</em></blockquote><p><em>To find the longest common prefix among an array of strings, we can use the following algorithm:</em></p><ol><li><em>If the array is empty, return an empty string since there are no common prefixes.</em></li><li><em>Initialize the prefix as the first string in the array.</em></li><li><em>Iterate through the remaining strings in the array.</em></li><li><em>For each string, compare it character by character with the current prefix.</em></li><li><em>Update the prefix to be the common prefix found so far.</em></li><li><em>Continue until all strings have been compared.</em></li><li><em>Return the final prefix.</em></li></ol><p><em>Here’s a Python implementation of the above algorithm:</em></p><pre>def longest_common_prefix(strs):<br>    if not strs:<br>        return &quot;&quot;<br><br>    prefix = strs[0]<br><br>    for string in strs[1:]:<br>        i = 0<br>        while i &lt; len(prefix) and i &lt; len(string) and prefix[i] == string[i]:<br>            i += 1<br>        prefix = prefix[:i]<br>        if prefix == &quot;&quot;:<br>            return &quot;&quot;<br><br>    return prefix<br><br># Example usage:<br>strs = [&quot;flower&quot;, &quot;flow&quot;, &quot;flight&quot;]<br>print(longest_common_prefix(strs))  # Output: &quot;fl&quot;</pre><p><em>This implementation iterates through each string in the array and compares it with the current prefix character by character. It updates the prefix to be the common prefix found so far. If at any point the prefix becomes empty (indicating no common prefix), the function returns an empty string. Otherwise, it returns the final prefix found.</em></p><p><strong>Java Code</strong></p><pre>public class LongestCommonPrefix {<br>    public static String longestCommonPrefix(String[] strs) {<br>        if (strs == null || strs.length == 0) {<br>            return &quot;&quot;;<br>        }<br><br>        // Find the shortest string in the array<br>        String shortest = strs[0];<br>        for (String str : strs) {<br>            if (str.length() &lt; shortest.length()) {<br>                shortest = str;<br>            }<br>        }<br><br>        // Initialize the prefix as the shortest string<br>        StringBuilder prefix = new StringBuilder(shortest);<br><br>        // Iterate through each string in the array<br>        for (String str : strs) {<br>            // Compare each character of the prefix with the current string<br>            for (int i = 0; i &lt; prefix.length(); i++) {<br>                if (prefix.charAt(i) != str.charAt(i)) {<br>                    // If a character mismatch is found, update the prefix<br>                    prefix.delete(i, prefix.length());<br>                    break;<br>                }<br>            }<br>        }<br><br>        return prefix.toString();<br>    }<br><br>    public static void main(String[] args) {<br>        String[] strs = {&quot;flower&quot;, &quot;flow&quot;, &quot;flight&quot;};<br>        System.out.println(longestCommonPrefix(strs)); // Output: &quot;fl&quot;<br>    }<br>}</pre><p><strong>JavaScript Code</strong></p><pre>function longestCommonPrefix(strs) {<br>    if (strs.length === 0) {<br>        return &quot;&quot;;<br>    }<br><br>    let prefix = strs[0];<br><br>    for (let i = 1; i &lt; strs.length; i++) {<br>        let j = 0;<br>        while (j &lt; prefix.length &amp;&amp; j &lt; strs[i].length &amp;&amp; prefix[j] === strs[i][j]) {<br>            j++;<br>        }<br>        prefix = prefix.slice(0, j);<br>        if (prefix === &quot;&quot;) {<br>            return &quot;&quot;;<br>        }<br>    }<br><br>    return prefix;<br>}<br><br>// Example usage:<br>const strs = [&quot;flower&quot;, &quot;flow&quot;, &quot;flight&quot;];<br>console.log(longestCommonPrefix(strs));  // Output: &quot;fl&quot;</pre><p><em>Now, let’s analyze the time complexity of this algorithm:</em></p><ul><li><em>Let n be the number of strings in the array, and let m be the average length of strings.</em></li><li><em>The algorithm iterates through each string once, performing character comparisons until it reaches the end of either the prefix or the current string.</em></li><li><em>In the worst case, each character in the prefix needs to be compared with each character in each string.</em></li><li><em>Therefore, the time complexity is </em><strong><em>O(n * m)</em></strong><em>, where n is the number of strings and m is the average length of strings in the array.</em></li></ul><p><em>This algorithm is simple and effective, providing a straightforward solution to finding the longest common prefix among an array of strings.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=78a446489fec" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Merging Two Linked Lists in Java: A Step-by-Step Guide with bonus tips at the end]]></title>
            <link>https://blog.devgenius.io/merging-two-linked-lists-in-java-a-step-by-step-guide-with-bonus-tips-at-the-end-d46712b843e5?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/d46712b843e5</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[data-structures]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Mon, 25 Mar 2024 14:39:33 GMT</pubDate>
            <atom:updated>2025-04-22T17:12:17.826Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wL7SNq6GX9nc8UL6jcGGTQ.jpeg" /></figure><p><strong>Buy book – </strong><a href="https://antesh6.gumroad.com/l/ourkj"><strong>Let’s talk about Coding Basics for young engineers</strong></a></p><p><em>Linked lists are fundamental data structures used to store and organize data. Merging two linked lists efficiently is a common task, especially when dealing with sorted data. In this guide, we’ll walk through a step-by-step approach to merging two linked lists in Java, complete with a practical example.</em></p><p><strong><em>Step 1: Initialize Pointers</em></strong></p><ul><li><em>Create a new linked list to store the merged result.</em></li><li><em>Initialize pointers for the two input linked lists and the result linked list.</em></li></ul><pre>class ListNode {<br>    int val;<br>    ListNode next;<br>    <br>    public ListNode(int val) {<br>        this.val = val;<br>    }<br>}<br><br>public class MergeLinkedLists {<br>    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {<br>        ListNode dummy = new ListNode(0); // Dummy node to simplify handling the head of the result list<br>        ListNode current = dummy;<br><br>        // Initialize pointers<br>        while (l1 != null &amp;&amp; l2 != null) {<br>            // Compare elements<br>            if (l1.val &lt;= l2.val) {<br>                current.next = l1;<br>                l1 = l1.next;<br>            } else {<br>                current.next = l2;<br>                l2 = l2.next;<br>            }<br><br>            current = current.next;<br>        }<br><br>        // Handle remaining elements<br>        current.next = (l1 != null) ? l1 : l2;<br><br>        return dummy.next; // Skip the dummy node when returning the result<br>    }<br>}</pre><p><strong><em>Step 2: Traverse and Compare</em></strong></p><ul><li><em>Traverse both input linked lists simultaneously.</em></li><li><em>Compare the current elements pointed to by the two pointers</em>.</li></ul><p><em>In this example, we define a </em><strong><em>ListNode</em></strong><em> class to represent each node in the linked list. The </em><strong><em>mergeTwoLists</em></strong><em> method takes two sorted linked lists (</em><strong><em>l1</em></strong><em> and </em><strong><em>l2</em></strong><em>) and merges them into a new sorted linked list.</em></p><p><strong><em>Step 3: Merge Elements</em></strong></p><ul><li><em>If the element in the first linked list is smaller (or equal), add it to the result linked list and move the pointer in the first list to the next element.</em></li><li><em>If the element in the second linked list is smaller, add it to the result linked list and move the pointer in the second list to the next element.</em></li></ul><p><em>The method traverses both input linked lists simultaneously, comparing elements at each step. The smaller (or equal) element is added to the result linked list, and the respective pointer is moved to the next element.</em></p><p><strong><em>Step 4: Handle Remaining Elements</em></strong></p><p><em>Continue this process until reaching the end of one of the linked lists. If one list is longer than the other, simply append the remaining elements to the result linked list.</em></p><p><strong><em>Step 5: Result Linked List</em></strong></p><p><em>The </em><strong><em>mergeTwoLists</em></strong><em> method returns the merged and sorted linked list.</em></p><p><strong><em>Python Example</em></strong></p><pre>class ListNode:<br>    def __init__(self, value=0, next=None):<br>        self.value = value<br>        self.next = next<br><br>def merge_linked_lists(l1, l2):<br>    dummy = ListNode()  # Dummy node to simplify handling the head of the result list<br>    current = dummy<br><br>    while l1 and l2:<br>        if l1.value &lt;= l2.value:<br>            current.next = l1<br>            l1 = l1.next<br>        else:<br>            current.next = l2<br>            l2 = l2.next<br><br>        current = current.next<br><br>    # If one list is longer than the other, append remaining elements<br>    current.next = l1 or l2<br><br>    return dummy.next  # Skip the dummy node when returning the result</pre><p><em>This approach assumes that the input linked lists are already sorted. If they are not, you may need to sort them first before merging.</em></p><p><strong><em>Bonus Tips</em></strong></p><blockquote><em>The flexibility and simplicity of linked lists make them suitable for scenarios where dynamic data structures are required, and constant-time insertions and deletions are essential. Despite their overhead in terms of pointers, linked lists shine in situations where the benefits of dynamic memory allocation and ease of modification outweigh their drawbacks.</em></blockquote><blockquote><strong><em>1. Dynamic Memory Allocation:</em></strong></blockquote><blockquote><em>Linked lists allow dynamic memory allocation, as they can easily grow or shrink in size during program execution. This is particularly useful when the size of the data structure is unknown in advance.</em></blockquote><blockquote><strong><em>2. Implementation of Other Data Structures:</em></strong></blockquote><blockquote><em>Linked lists are used to implement more complex data structures like stacks and queues. For example, a linked list can be employed to create a dynamic stack where elements can be easily added or removed.</em></blockquote><blockquote><strong><em>3. File Systems:</em></strong></blockquote><blockquote><em>Linked lists are used in file systems to maintain the structure of directories. Each directory contains a linked list of entries, where each entry points to a file or a sub-directory.</em></blockquote><blockquote><strong><em>4. Symbol Tables:</em></strong></blockquote><blockquote><em>In compilers and interpreters, linked lists are often used to implement symbol tables, where variables and their associated information are stored.</em></blockquote><blockquote><strong><em>5. Dynamic Hashing:</em></strong></blockquote><blockquote><em>Linked lists are used in dynamic hashing to handle collisions. When two keys hash to the same location, a linked list at that location can store all the elements with the same hash value.</em></blockquote><blockquote><strong><em>5. Memory Management in Operating Systems:</em></strong></blockquote><blockquote><em>In operating systems, linked lists are used to manage memory. Free memory blocks are stored in a linked list, and when memory is allocated or deallocated, the linked list is updated accordingly.</em></blockquote><blockquote><strong><em>7. Graph Representation:</em></strong></blockquote><blockquote><em>Linked lists can be used to represent graphs. Each node in the linked list can represent a vertex, and the edges between vertices are represented by the links between nodes.</em></blockquote><blockquote><strong><em>8. Undo Functionality in Software:</em></strong></blockquote><blockquote><em>In applications with undo functionality, a linked list can be used to store a sequence of states. Each state change corresponds to a node in the linked list.</em></blockquote><blockquote><strong><em>9. Music Player Playlist:</em></strong></blockquote><blockquote><em>Playlists in music players can be implemented using linked lists. Each song can be represented as a node, and the links between nodes define the order of the playlist.</em></blockquote><blockquote><strong><em>10. Polynomial Representation:</em></strong></blockquote><blockquote><em>Linked lists are used to represent polynomials, especially in algebraic operations. Each node represents a term in the polynomial.</em></blockquote><p><em>Feel free to incorporate this Java example into your projects or use it as a reference when working with linked lists and data merging tasks.</em></p><p><em>Joly coding!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d46712b843e5" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/merging-two-linked-lists-in-java-a-step-by-step-guide-with-bonus-tips-at-the-end-d46712b843e5">Merging Two Linked Lists in Java: A Step-by-Step Guide with bonus tips at the end</a> was originally published in <a href="https://blog.devgenius.io/">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Demystifying Dynamic Programming: A Guide to Optimizing Problem-Solving]]></title>
            <link>https://medium.com/@coffee_addiction/demystifying-dynamic-programming-a-guide-to-optimizing-problem-solving-fcd9cfafe626?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/fcd9cfafe626</guid>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[problem-solving]]></category>
            <category><![CDATA[dynamic-programming]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Sat, 23 Mar 2024 19:41:12 GMT</pubDate>
            <atom:updated>2025-04-19T03:37:58.135Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/769/1*sLBlBe5iOisQWfkCY7mPjQ.png" /><figcaption>Dynamic Programming</figcaption></figure><p><strong>Buy book:</strong> Let’s talk about <strong>Coding Basics </strong>for young engineers <a href="https://antesh6.gumroad.com/l/ourkj">https://antesh6.gumroad.com/l/ourkj</a></p><p><em>Dynamic programming is a powerful technique for solving complex problems by breaking them down into simpler subproblems and solving each subproblem only once. The key insight behind dynamic programming is to solve each subproblem only once and store the solution, so that it can be reused whenever needed. This approach helps avoid redundant computations and dramatically improves the efficiency of the solution. It is particularly useful for optimization problems where the goal is to find the best solution among a set of possible solutions.</em></p><h3><em>Key Principles of Dynamic Programming</em></h3><ol><li><strong><em>Overlapping Subproblems:</em></strong><em> Dynamic programming is most effective when the problem exhibits overlapping subproblems, meaning that the same subproblems are encountered multiple times during the computation.</em></li><li><strong><em>Optimal Substructure:</em></strong><em> The problem must have optimal substructure, which means that the optimal solution to the larger problem can be constructed from optimal solutions to its subproblems. This property allows us to build up the solution iteratively.</em></li><li><strong><em>Memoization vs. Tabulation:</em></strong><em> Dynamic programming can be implemented using two main approaches: </em><strong><em>memoization and tabulation</em></strong><em>. </em><strong><em>Memoization </em></strong><em>involves storing the solutions to subproblems in a data structure (such as a dictionary or array), while </em><strong><em>tabulation </em></strong><em>involves solving subproblems in a bottom-up manner, starting with the smallest subproblems and gradually building up to the larger problem.</em></li></ol><h3><em>Applications of Dynamic Programming</em></h3><p><em>Dynamic programming has a wide range of applications across various domains, including:</em></p><ul><li><strong><em>Algorithm Design:</em></strong><em> Dynamic programming is commonly used to solve optimization problems, such as the </em><strong><em>knapsack problem</em></strong><em>, </em><strong><em>longest common subsequence</em></strong><em>, and </em><strong><em>shortest path problems</em></strong><em>.</em></li><li><strong><em>Sequence Alignment:</em></strong><em> In bioinformatics, dynamic programming is used to align sequences of DNA, RNA, or proteins to identify similarities and differences.</em></li><li><strong><em>Resource Allocation: </em></strong><em>Dynamic programming can be applied to optimize resource allocation in various scenarios, such as </em><strong><em>project scheduling</em></strong><em>, </em><strong><em>production planning</em></strong><em>, and </em><strong><em>inventory management</em></strong><em>.</em></li></ul><h3><em>Conclusion</em></h3><p><em>Dynamic programming is a versatile and powerful technique that can greatly enhance problem-solving capabilities. By breaking down complex problems into simpler subproblems and efficiently solving them, dynamic programming offers elegant solutions to a wide range of challenges. Whether you’re a seasoned programmer or just getting started, understanding the principles of dynamic programming can open up new avenues for tackling complex problems and optimizing your code.</em></p><p><em>In future posts, we’ll delve deeper into specific dynamic programming problems and explore practical examples of how dynamic programming can be applied to solve real-world challenges. Stay tuned!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fcd9cfafe626" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Greedy algorithm and optimized solution for Coin Change Problem]]></title>
            <link>https://medium.com/@coffee_addiction/greedy-algorithm-and-optimized-solution-for-coin-change-problem-b7171c296a2d?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/b7171c296a2d</guid>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Sat, 23 Mar 2024 19:30:51 GMT</pubDate>
            <atom:updated>2025-04-19T03:38:44.885Z</atom:updated>
            <content:encoded><![CDATA[<h3><em>Greedy algorithm and optimized solution for Coin Change Problem</em><strong><em>Description: </em></strong><em>Given a set of coin denominations and a target amount, find the minimum number of coins needed to make up that amount.</em></h3><p><strong>Buy book:</strong> Let’s talk about <strong>Coding Basics</strong> for young engineers <a href="https://antesh6.gumroad.com/l/ourkj">https://antesh6.gumroad.com/l/ourkj</a></p><p><em>The Coin Change Problem is a classic optimization problem often solved using dynamic programming or greedy algorithms. Here, I’ll provide both a greedy algorithm and an optimized dynamic programming solution</em></p><p><strong><em>Example:</em></strong><em> For target amount 36 and coin denominations [1, 5, 10, 25], the greedy algorithm would select 25, 10, and 1, totaling 36.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1009/1*PRFXKJIOGk9c34PNdXPUZA.jpeg" /><figcaption>Coin Change Problem</figcaption></figure><h3><em>Greedy Algorithm</em></h3><p><em>In the greedy algorithm for the coin change problem, we sort the coin denominations in descending order and then iteratively select the largest denomination coin that is less than or equal to the remaining amount. This process continues until the remaining amount becomes zero.</em></p><pre>def coin_change_greedy(coins, amount):<br>    # Sort coins in descending order<br>    coins.sort(reverse=True)  <br>    <br>    num_coins = 0<br>    for coin in coins:<br>        if amount == 0:<br>            break<br>        num_coins += amount // coin<br>        amount %= coin<br>    <br>    if amount == 0:<br>        return num_coins  # If amount is zero, return the number of coins used<br>    else:<br>        return -1  # If change cannot be made, return -1<br><br># Example usage:<br>coins = [1, 5, 10, 25]  # Coin denominations<br>amount = 36<br>print(&quot;Minimum number of coins (greedy):&quot;, coin_change_greedy(coins, amount))</pre><p><em>This implementation sorts the coins in descending order and then iterates through the coins, selecting the largest denomination coins that can be used while decrementing the remaining amount. It returns the total number of coins used if change can be made, or -1 if change cannot be made. Note that this greedy algorithm may not always produce the optimal solution for arbitrary coin denominations.</em></p><p><strong><em>Time Complexity Analysis</em></strong></p><ul><li><em>Sorting the coins initially takes </em><strong><em>O(n log n) </em></strong><em>time, where n is the number of coin denominations.</em></li><li><em>The main loop iterates over each coin denomination once, resulting in a linear time complexity of </em><strong><em>O(n)</em></strong><em>.</em></li><li><em>Overall, the time complexity of the greedy algorithm for the coin change problem is </em><strong><em>O(n log n)</em></strong><em> due to the sorting step.</em></li></ul><p><em>It’s important to note that while the greedy algorithm has a time complexity of </em><strong><em>O(n log n)</em></strong><em> due to sorting, in many practical cases where the number of coin denominations is small and the denominations are known in advance, the sorting step can be considered negligible, resulting in a linear time complexity of </em><strong><em>O(n)</em></strong><em> for the algorithm. However, if the number of coin denominations is large and unknown, or if the denominations are dynamically changing, the sorting step may become significant.</em></p><h3><em>Optimized Dynamic Programming Solution</em></h3><p><em>The dynamic programming solution for the coin change problem involves building a table where each cell represents the minimum number of coins needed to make up the corresponding amount. We iteratively fill the table using the minimum of either including the current coin or excluding it.</em></p><ol><li><strong><em>Initialization</em></strong></li></ol><ul><li><em>We start by initializing a dynamic programming array </em><em>dp, where </em><em>dp[i] represents the minimum number of coins needed to make up the amount </em><em>i.</em></li><li><em>Initially, we set all values in </em><em>dp to infinity, except for </em><em>dp[0], which is set to 0 because no coins are needed to make up the amount 0.</em></li></ul><p><strong><em>2. Iterative Filling of DP Table</em></strong></p><ul><li><em>We iterate over each coin denomination in the </em><em>coins array.</em></li><li><em>For each coin denomination </em><em>coin, we iterate over all possible amounts from </em><em>coin to </em><em>amount.</em></li><li><em>At each iteration, we update the value of </em><em>dp[i] to be the minimum of its current value and </em><em>dp[i - coin] + 1.</em></li><li><em>This represents the optimal solution for the current amount </em><em>i, considering whether or not to include the current coin denomination </em><em>coin.</em></li></ul><p><em>3. </em><strong><em>Final Result</em></strong></p><ul><li><em>After filling the entire </em><em>dp table, the value of </em><em>dp[amount] represents the minimum number of coins needed to make up the given amount.</em></li><li><em>If </em><em>dp[amount] is still infinity, it means that it is not possible to make up the amount using the available coin denominations, so we return </em><em>-1.</em></li></ul><pre>def coin_change_dp(coins, amount):<br>    dp = [float(&#39;inf&#39;)] * (amount + 1)<br>    dp[0] = 0  # Base case: 0 coins needed for amount 0<br>    <br>    for coin in coins:<br>        for i in range(coin, amount + 1):<br>            dp[i] = min(dp[i], dp[i - coin] + 1)<br>    <br>    return dp[amount] if dp[amount] != float(&#39;inf&#39;) else -1  # If change cannot be made, return -1<br><br># Example usage:<br>coins = [1, 5, 10, 25]  # Coin denominations<br>amount = 36<br>print(&quot;Minimum number of coins (DP):&quot;, coin_change_dp(coins, amount))</pre><h3><em>Time Complexity Analysis:</em></h3><p><em>Let’s analyze the time complexity of the dynamic programming solution:</em></p><p><strong><em>Initialization</em></strong></p><p><em>Initializing the </em><em>dp array takes constant time, O(1).</em></p><p><strong><em>Filling DP Table:</em></strong></p><ul><li><em>We have a nested loop structure:</em></li><li><em>The outer loop iterates over each coin denomination, taking O(N) time, where N is the number of coin denominations.</em></li><li><em>The inner loop iterates over all possible amounts from </em><em>coin to </em><em>amount, taking O(amount) time.</em></li><li><em>Therefore, the total time complexity for filling the DP table is O(N * amount), where N is the number of coin denominations and amount is the given target amount.</em></li></ul><p><strong><em>Final Result</em></strong></p><p><em>Determining the final result by accessing </em><em>dp[amount] takes constant time, O(1).</em></p><h3><em>Overall Time Complexity</em></h3><p><em>The dominant factor in the time complexity is the filling of the DP table, which is </em><strong><em>O(N * amount)</em></strong><em>, where N is the number of coin denominations and amount is the given target amount. The initialization and determining the final result both contribute constant time, so they do not significantly affect the overall time complexity.</em></p><p><em>In summary, the time complexity of the optimized dynamic programming solution for the coin change problem is </em><strong><em>O(N * amount)</em></strong><em>, where N is the number of coin denominations and amount is the given target amount.</em></p><p><em>Both solutions provide the minimum number of coins needed to make up the given amount. The greedy algorithm may not always produce the optimal solution for arbitrary coin denominations, while the dynamic programming solution guarantees the optimal solution. However, the greedy algorithm is often faster and simpler.</em></p><p><em>Joly Coding!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b7171c296a2d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What’s Greedy algorithm, it’s time and space complexity?]]></title>
            <link>https://medium.com/@coffee_addiction/whats-greedy-algorithm-it-s-time-and-space-complexity-f124368bb0dc?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/f124368bb0dc</guid>
            <category><![CDATA[python]]></category>
            <category><![CDATA[greedy-algorithms]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Sat, 23 Mar 2024 18:59:00 GMT</pubDate>
            <atom:updated>2025-04-19T03:39:57.977Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Kvvax8LZleSDkJG-OJpjCQ@2x.jpeg" /></figure><p><strong>Buy book: </strong>Let’s talk about <strong>Coding Basics </strong>for young engineers <a href="https://antesh6.gumroad.com/l/ourkj">https://antesh6.gumroad.com/l/ourkj</a></p><p><em>A greedy algorithm is an approach to problem-solving that involves making locally optimal choices at each step with the hope of finding a globally optimal solution. At each step, the algorithm selects the best available option without considering the consequences of that choice on future steps. Greedy algorithms are typically used for optimization problems, where the goal is to find the best solution from a set of possible solutions.</em></p><p><em>Here are the basic steps involved in designing and implementing a greedy algorithm:</em></p><p><strong><em>Define the Problem</em></strong></p><p><em>Clearly define the problem you are trying to solve and the criteria for optimization.</em></p><p><strong><em>Identify Greedy Choice Property</em></strong></p><p><em>Determine the property that allows you to make greedy choices at each step. This property ensures that selecting the locally optimal solution leads to an optimal solution overall.</em></p><p><strong><em>Design the Algorithm</em></strong></p><p><em>Develop a strategy to iteratively make greedy choices and update the solution.</em></p><p><strong><em>Implement the Algorithm</em></strong></p><p><em>Write the algorithm using a programming language of your choice, ensuring that it follows the greedy strategy defined earlier.</em></p><p><strong><em>Analyze the Solution</em></strong></p><p><em>After obtaining the solution, analyze its correctness and optimality. Sometimes, you may need to prove that the greedy algorithm always produces the optimal solution for the given problem.</em></p><p><strong><em>Optimization and Refinement</em></strong></p><p><em>If necessary, refine the algorithm to improve its performance or to handle additional constraints.</em></p><p><em>Example problems where greedy algorithms are commonly applied include:</em></p><ul><li><strong><em>Coin Change Problem:</em></strong><em> Given a set of coin denominations and a target amount, find the minimum number of coins needed to make up that amount.</em></li><li><strong><em>Fractional Knapsack Problem:</em></strong><em> Given a set of items with weights and values, and a knapsack with a maximum weight capacity, determine the maximum value of items to include in the knapsack without exceeding its capacity.</em></li><li><strong><em>Minimum Spanning Tree:</em></strong><em> Given a graph with weighted edges, find a spanning tree with the minimum total weight.</em></li><li><strong><em>Huffman Coding:</em></strong><em> Given a set of characters and their frequencies, find an optimal binary prefix code that minimizes the total encoded message length.</em></li></ul><h3><em>Time Complexity</em></h3><p><em>The time complexity of a greedy algorithm is determined by the number of iterations required to find the solution. In many cases, greedy algorithms have linear or polynomial time complexity, making them efficient for solving large instances of problems. However, the time complexity can also be exponential or even worse in some cases, especially if the problem has a combinatorial nature.</em></p><h3><em>Space Complexity</em></h3><p><em>The space complexity of a greedy algorithm depends on the data structures used to represent the problem instance and the solution. Typically, greedy algorithms require only a constant amount of additional space beyond the input data, resulting in constant space complexity. However, this may vary depending on the problem and the specific implementation.</em></p><p><em>It’s important to note that while greedy algorithms are often simple and efficient, they may not always produce the optimal solution for every problem. In some cases, a greedy approach may lead to a suboptimal solution that is not globally optimal. Therefore, it’s essential to carefully analyze the problem and ensure that the greedy choice property holds to guarantee the correctness of the solution.</em></p><p><em>Overall, the time and space complexity of a greedy algorithm can vary depending on the problem and the specific implementation details. It’s important to analyze the complexity of each greedy algorithm on a case-by-case basis to understand its efficiency and performance characteristics.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f124368bb0dc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Window Sliding Technique — Find the maximum sum subarray of a fixed size k]]></title>
            <link>https://blog.devgenius.io/window-sliding-technique-find-the-maximum-sum-subarray-of-a-fixed-size-k-4d153b640562?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/4d153b640562</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Fri, 01 Dec 2023 14:17:30 GMT</pubDate>
            <atom:updated>2025-04-19T03:36:04.675Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong><em>Window Sliding Technique — </em></strong><em>Find the maximum sum subarray of a fixed size k</em></h3><p><strong>Buy my book: Let’s talk about Coding Basics for young engineers </strong><a href="https://antesh6.gumroad.com/l/ourkj">https://antesh6.gumroad.com/l/ourkj</a></p><p><em>The window sliding technique using two pointers is an efficient approach to solving problems where you need to maintain a subarray or subsequence of a certain size while iterating through an array. The idea is to maintain a window of size </em><em>k and slide it through the array while keeping track of the sum.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uAOd8VLkR9kk2bQvtsM5BA@2x.jpeg" /></figure><h3><em>Window Sliding Technique using Two Pointers</em></h3><ol><li><strong><em>Initialize Pointers:</em></strong><em> Start with two pointers, usually named </em><em>left and </em><em>right, and set them to the beginning of the array.</em></li><li><strong><em>Maintain the Window:</em></strong><em> Move the </em><em>right pointer to the right to expand the window while keeping the </em><em>left pointer fixed. This is done until the desired window of size k is reached.</em></li><li><strong><em>Update Information:</em></strong><em> While expanding the window, update the information you need (e.g., sum, product, frequency, etc.). In this case, calculate the sum of elements within the window. Update the maximum sum if the current sum is greater.</em></li><li><strong><em>Shrink the Window: </em></strong><em>Once the window size is reached, move the </em><em>left pointer to the right to shrink the window. Again, update the maximum sum if the current sum is greater. Move the window by incrementing both pointers.</em></li><li><strong><em>Repeat:</em></strong><em> Continue steps 2–4 until the </em><em>right pointer reaches the end of the array.</em></li></ol><h3><em>Approach</em></h3><ul><li><em>Use two pointers, </em><em>left and </em><em>right, to maintain the window.</em></li><li><em>Use a variable to keep track of the current sum within the window.</em></li><li><em>Update the maximum sum whenever a new maximum is found.</em></li></ul><h3><em>Example — Maximum Sum Subarray of Size K</em></h3><pre>def max_sum_subarray(arr, k):<br>    if k &gt; len(arr) or k &lt;= 0:<br>        return &quot;Invalid input: k is not valid&quot;<br><br>    left = 0<br>    right = 0<br>    current_sum = 0<br>    max_sum = float(&#39;-inf&#39;)<br><br>    while right &lt; len(arr):<br>        # Expand the window<br>        current_sum += arr[right]<br><br>        # Check if the window size is reached<br>        if right - left + 1 == k:<br>            max_sum = max(max_sum, current_sum)<br><br>            # Shrink the window<br>            current_sum -= arr[left]<br>            left += 1<br><br>        # Move the right pointer to the right<br>        right += 1<br><br>    return max_sum<br><br># Example usage:<br>arr = [1, 4, 2, 10, 2, 3, 1, 0, 20]<br>k = 3<br>result = max_sum_subarray(arr, k)<br>print(f&quot;Maximum sum subarray of size {k}: {result}&quot;)</pre><p><em>In this example, the </em><em>max_sum_subarray function uses the window sliding technique with two pointers to find the maximum sum subarray of size </em><em>k. The </em><em>left and </em><em>right pointers are used to maintain the window, and the </em><em>current_sum variable is updated accordingly. The maximum sum is updated whenever the window size is reached.</em></p><p><strong><em>JavaScript</em></strong></p><pre>function maxSumSubarray(arr, k) {<br>  let left = 0;<br>  let right = 0;<br>  let currentSum = 0;<br>  let maxSum = 0;<br><br>  // Calculate sum for the first window<br>  for (let i = 0; i &lt; k; i++) {<br>    currentSum += arr[i];<br>  }<br><br>  // Slide the window through the array<br>  while (right &lt; arr.length) {<br>    // Update maxSum if currentSum is greater<br>    maxSum = Math.max(maxSum, currentSum);<br><br>    // Slide the window by moving left and right pointers<br>    currentSum = currentSum - arr[left] + arr[right];<br>    left++;<br>    right++;<br>  }<br><br>  return maxSum;<br>}<br><br>// Example usage:<br>const array = [4, 2, 1, 7, 8, 1, 2, 8, 1, 0];<br>const k = 3;<br>const result = maxSumSubarray(array, k);<br>console.log(&quot;Maximum Sum Subarray of size&quot;, k, &quot;is:&quot;, result);</pre><p><strong><em>Java</em></strong></p><pre>public class MaxSumSubarray {<br><br>    public static int findMaxSumSubarray(int[] nums, int k) {<br>        if (nums == null || nums.length == 0 || k &lt;= 0 || k &gt; nums.length) {<br>            throw new IllegalArgumentException(&quot;Invalid input&quot;);<br>        }<br><br>        int maxSum = Integer.MIN_VALUE;<br>        int currentSum = 0;<br><br>        // Initialize the window<br>        for (int i = 0; i &lt; k; i++) {<br>            currentSum += nums[i];<br>        }<br><br>        // Move the window<br>        for (int end = k; end &lt; nums.length; end++) {<br>            currentSum += nums[end] - nums[end - k]; // Slide the window<br><br>            // Update the maximum sum<br>            maxSum = Math.max(maxSum, currentSum);<br>        }<br><br>        return maxSum;<br>    }<br><br>    public static void main(String[] args) {<br>        int[] nums = {1, 4, 2, 10, 2, 3, 1, 0, 20};<br>        int k = 4;<br><br>        int result = findMaxSumSubarray(nums, k);<br>        System.out.println(&quot;Maximum sum subarray of size &quot; + k + &quot;: &quot; + result);<br>    }<br>}</pre><p><strong><em>Time Complexity</em></strong></p><p><em>The time complexity of this algorithm is O(N), where N is the length of the input array. This is because we only iterate through the array once.</em></p><p><strong><em>Note: </em></strong><em>This code assumes that the input array and the size of the subarray are valid. You may want to add additional input validation based on your specific requirements.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4d153b640562" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/window-sliding-technique-find-the-maximum-sum-subarray-of-a-fixed-size-k-4d153b640562">Window Sliding Technique — Find the maximum sum subarray of a fixed size k</a> was originally published in <a href="https://blog.devgenius.io/">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Algorithm, Time complexity to check if a linked list is a palindrome]]></title>
            <link>https://blog.devgenius.io/algorithm-time-complexity-to-check-if-a-linked-list-is-a-palindrome-249adf5f3e29?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/249adf5f3e29</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Sun, 26 Nov 2023 19:11:51 GMT</pubDate>
            <atom:updated>2025-04-19T03:40:44.365Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Buy book:</strong> Let’s talk about <strong>Coding Basics</strong> for young engineers <a href="https://antesh6.gumroad.com/l/ourkj">https://antesh6.gumroad.com/l/ourkj</a></p><p>Identifying if a linked list is a palindrome, is one of the classic examples of slow and fast pointers. To check if a linked list is a palindrome, you can follow these steps:</p><p>1.	Find the middle of the linked list.</p><p>2.	Reverse the second half of the linked list.</p><p>3.	Compare the reversed second half with the first half.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SS0_Iowf5_0mjKzAjGfduA@2x.jpeg" /></figure><p>Here’s the implementation along with the time complexity analysis</p><p><strong>Python</strong></p><pre>class ListNode:<br>    def __init__(self, val=0, next=None):<br>        self.val = val<br>        self.next = next<br><br>def isPalindrome(head):<br>    # Step 1: Find the middle of the linked list<br>    slow = fast = head<br>    while fast and fast.next:<br>        slow = slow.next<br>        fast = fast.next.next<br><br>    # Step 2: Reverse the second half of the linked list<br>    prev, curr = None, slow<br>    while curr:<br>        next_node = curr.next<br>        curr.next = prev<br>        prev = curr<br>        curr = next_node<br><br>    # Step 3: Compare the reversed second half with the first half<br>    first_half, second_half = head, prev<br>    while second_half:<br>        if first_half.val != second_half.val:<br>            return False<br>        first_half = first_half.next<br>        second_half = second_half.next<br><br>    return True<br><br># Example usage:<br>node1 = ListNode(1)<br>node2 = ListNode(2)<br>node3 = ListNode(2)<br>node4 = ListNode(1)<br><br>node1.next = node2<br>node2.next = node3<br>node3.next = node4<br><br>print(isPalindrome(node1))  # Output: True</pre><p>JavaScript</p><pre>class ListNode {<br>  constructor(val, next = null) {<br>    this.val = val;<br>    this.next = next;<br>  }<br>}<br><br>function isPalindrome(head) {<br>  // Step 1: Find the middle of the linked list<br>  let slow = head;<br>  let fast = head;<br>  while (fast &amp;&amp; fast.next) {<br>    slow = slow.next;<br>    fast = fast.next.next;<br>  }<br><br>  // Step 2: Reverse the second half of the linked list<br>  let prev = null;<br>  let curr = slow;<br>  while (curr) {<br>    let nextNode = curr.next;<br>    curr.next = prev;<br>    prev = curr;<br>    curr = nextNode;<br>  }<br><br>  // Step 3: Compare the reversed second half with the first half<br>  let firstHalf = head;<br>  let secondHalf = prev;<br>  while (secondHalf) {<br>    if (firstHalf.val !== secondHalf.val) {<br>      return false;<br>    }<br>    firstHalf = firstHalf.next;<br>    secondHalf = secondHalf.next;<br>  }<br><br>  return true;<br>}<br><br>// Example usage:<br>const node1 = new ListNode(1);<br>const node2 = new ListNode(2);<br>const node3 = new ListNode(2);<br>const node4 = new ListNode(1);<br><br>node1.next = node2;<br>node2.next = node3;<br>node3.next = node4;<br><br>console.log(isPalindrome(node1));  // Output: true</pre><p>Java</p><pre>class ListNode {<br>    int val;<br>    ListNode next;<br><br>    ListNode(int val) {<br>        this.val = val;<br>    }<br>}<br><br>public class PalindromeLinkedList {<br><br>    public boolean isPalindrome(ListNode head) {<br>        // Step 1: Find the middle of the linked list<br>        ListNode slow = head;<br>        ListNode fast = head;<br>        while (fast != null &amp;&amp; fast.next != null) {<br>            slow = slow.next;<br>            fast = fast.next.next;<br>        }<br><br>        // Step 2: Reverse the second half of the linked list<br>        ListNode reversedSecondHalf = reverseList(slow);<br><br>        // Step 3: Compare the reversed second half with the first half<br>        ListNode firstHalf = head;<br>        while (reversedSecondHalf != null) {<br>            if (firstHalf.val != reversedSecondHalf.val) {<br>                return false;<br>            }<br>            firstHalf = firstHalf.next;<br>            reversedSecondHalf = reversedSecondHalf.next;<br>        }<br><br>        return true;<br>    }<br><br>    private ListNode reverseList(ListNode head) {<br>        ListNode prev = null;<br>        ListNode curr = head;<br>        while (curr != null) {<br>            ListNode nextNode = curr.next;<br>            curr.next = prev;<br>            prev = curr;<br>            curr = nextNode;<br>        }<br>        return prev;<br>    }<br><br>    public static void main(String[] args) {<br>        PalindromeLinkedList palindromeLinkedList = new PalindromeLinkedList();<br><br>        // Example usage:<br>        ListNode node1 = new ListNode(1);<br>        ListNode node2 = new ListNode(2);<br>        ListNode node3 = new ListNode(2);<br>        ListNode node4 = new ListNode(1);<br><br>        node1.next = node2;<br>        node2.next = node3;<br>        node3.next = node4;<br><br>        System.out.println(palindromeLinkedList.isPalindrome(node1));  // Output: true<br>    }<br>}</pre><p><strong>Time Complexity</strong></p><p>•	Finding the middle of the linked list: O(n)</p><p>•	Reversing the second half: O(n/2) =&gt; O(n)</p><p>•	Comparing the two halves: O(n/2) =&gt; O(n)</p><p>The overall time complexity is O(n). The space complexity is O(1) since we are reversing the linked list in-place without using extra space proportional to the input size.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=249adf5f3e29" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/algorithm-time-complexity-to-check-if-a-linked-list-is-a-palindrome-249adf5f3e29">Algorithm, Time complexity to check if a linked list is a palindrome</a> was originally published in <a href="https://blog.devgenius.io/">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Find the middle of a linked list using two pointers and it’s time complexity]]></title>
            <link>https://blog.devgenius.io/find-the-middle-of-a-linked-list-using-two-pointers-and-its-time-complexity-cc8f69a67d60?source=rss-3ab1bab6c30f------2</link>
            <guid isPermaLink="false">https://medium.com/p/cc8f69a67d60</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Antesh Sharma]]></dc:creator>
            <pubDate>Fri, 24 Nov 2023 21:16:49 GMT</pubDate>
            <atom:updated>2025-04-19T03:41:27.075Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Buy book:</strong> Let’s talk about <strong>Coding Basics</strong> for young engineers <a href="https://antesh6.gumroad.com/l/ourkj">https://antesh6.gumroad.com/l/ourkj</a></p><p><em>Finding the middle of a linked list using two pointers is a common algorithmic problem. The approach involves using two pointers, one moving one step at a time (slow pointer) and the other moving two steps at a time (fast pointer). When the fast pointer reaches the end of the linked list, the slow pointer will be at the middle.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*Rv9Xm9dve3HC5kUPSgHPjA.jpeg" /><figcaption>Two Pointers Pattern</figcaption></figure><p><em>Here’s an example implementation in Python</em></p><pre>class ListNode:<br>    def __init__(self, val=0, next=None):<br>        self.val = val<br>        self.next = next<br><br>def findMiddle(head):<br>    if not head:<br>        return None<br><br>    slow = head<br>    fast = head<br><br>    while fast and fast.next:<br>        slow = slow.next<br>        fast = fast.next.next<br><br>    return slow</pre><p><em>In this implementation, the </em><em>findMiddle function takes the head of the linked list as input and returns the middle node. The termination condition for the while loop allows the fast pointer to reach the end, and the slow pointer lands exactly at the middle node for an odd-length linked list.</em></p><p><strong><em>When the length of the linked list is</em></strong><em> </em><strong><em>odd</em></strong><em>, finding the middle involves advancing the slow pointer one extra step to land exactly at the middle node. The algorithm remains similar to the one for an even-length linked list but with a slight modification in the termination condition.</em></p><p><strong><em>When the length of the linked list is even,</em></strong><em> the fast pointer reaches the end of the linked list, the slow pointer will be at the middle or the first middle node in the case of an even-length list.</em></p><pre>class ListNode {<br>    int val;<br>    ListNode next;<br><br>    ListNode(int val) {<br>        this.val = val;<br>    }<br>}<br><br>public class LinkedListMiddle {<br>    public static ListNode findMiddle(ListNode head) {<br>        if (head == null) {<br>            return null;<br>        }<br><br>        ListNode slow = head;<br>        ListNode fast = head;<br><br>        while (fast != null &amp;&amp; fast.next != null) {<br>            slow = slow.next;<br>            fast = fast.next.next;<br>        }<br><br>        return slow;<br>    }<br><br>    public static void main(String[] args) {<br>        // Example usage for Odd length linked list:<br>        ListNode head = new ListNode(1);<br>        head.next = new ListNode(2);<br>        head.next.next = new ListNode(3);<br>        head.next.next.next = new ListNode(4);<br>        head.next.next.next.next = new ListNode(5);<br><br>        ListNode middleNode = findMiddle(head);<br><br>        System.out.println(middleNode.val); // Output: 3<br>    }<br>}</pre><pre><br>class ListNode {<br>    int val;<br>    ListNode next;<br><br>    ListNode(int val) {<br>        this.val = val;<br>    }<br>}<br><br>public class LinkedListMiddle {<br>    public static ListNode findMiddle(ListNode head) {<br>        if (head == null) {<br>            return null;<br>        }<br><br>        ListNode slow = head;<br>        ListNode fast = head;<br><br>        while (fast != null &amp;&amp; fast.next != null) {<br>            slow = slow.next;<br>            fast = fast.next.next;<br>        }<br><br>        return slow;<br>    }<br><br>    public static void main(String[] args) {<br>        // Example usage for even length linked list:<br>        ListNode head = new ListNode(1);<br>        head.next = new ListNode(2);<br>        head.next.next = new ListNode(3);<br>        head.next.next.next = new ListNode(4);<br>        head.next.next.next.next = new ListNode(5);<br>        head.next.next.next.next.next = new ListNode(6);<br><br>        ListNode middleNode = findMiddle(head);<br><br>        System.out.println(middleNode.val); // Output: 3, first middle<br>    }<br>}</pre><p><em>The termination condition of the loop is when the fast pointer reaches the end or </em><em>null. In the case of an even-length list, the slow pointer will be at the first middle node.</em></p><p><strong><em>Time Complexity:</em></strong></p><p><em>The time complexity of finding the middle of a linked list using two pointers is O(n), where n is the number of nodes in the linked list.</em></p><p><strong><em>Bonus Point</em></strong></p><p><em>The reason is that the fast pointer moves twice as fast as the slow pointer. In each iteration, the slow pointer advances by one node, and the fast pointer advances by two nodes. The fast pointer will reach the end of the list after approximately n/2 iterations, where n is the total number of nodes. The termination condition is when the fast pointer reaches the end of the linked list. Therefore, the time complexity is linear with respect to the number of nodes in the linked list.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cc8f69a67d60" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/find-the-middle-of-a-linked-list-using-two-pointers-and-its-time-complexity-cc8f69a67d60">Find the middle of a linked list using two pointers and it’s time complexity</a> was originally published in <a href="https://blog.devgenius.io/">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>