<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: JB</title>
    <description>The latest articles on DEV Community by JB (@jjb).</description>
    <link>https://dev.to/jjb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F261666%2F44cd0463-f41b-4bea-8dce-78c4bdb39bb5.png</url>
      <title>DEV Community: JB</title>
      <link>https://dev.to/jjb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jjb"/>
    <language>en</language>
    <item>
      <title>Traveling Salesman Problem</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Sat, 13 Jun 2020 00:43:49 +0000</pubDate>
      <link>https://dev.to/jjb/traveling-salesman-problem-32c5</link>
      <guid>https://dev.to/jjb/traveling-salesman-problem-32c5</guid>
      <description>&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://nbviewer.jupyter.org/url/norvig.com/ipython/TSP.ipynb"&gt;In depth explanation + implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem"&gt;Wikipedia article&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The traveling salesman problem (TSP) is:

&lt;ul&gt;
&lt;li&gt;Given a list of cities &amp;amp; the distances between each pair of cities: what is the shortest possible route/tour that visits each city and returns to the origin city?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;With vanilla TSP you can assume the following:

&lt;ul&gt;
&lt;li&gt;The distance &lt;code&gt;D&lt;/code&gt; between city &lt;code&gt;A&lt;/code&gt; and city &lt;code&gt;B&lt;/code&gt; is the same as the distance between city &lt;code&gt;B&lt;/code&gt; and city &lt;code&gt;A&lt;/code&gt;. Thus, &lt;code&gt;D[A][B] == D[B][A]&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;If this is not true, TSP (&amp;amp; our graph of cities/distances) is considered asymmetric - a solution is more challenging to arrive at as there are more edges/possible routes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;There is no given origin/start city. We only care about the shortest (optimal) route.

&lt;ul&gt;
&lt;li&gt;If we must find the optimal route given a starting city, the solution is largely the same.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TSP is an &lt;a href="https://dev.to/jjb/part-15-np-complete-fibonacci-heap-2k79"&gt;NP-hard problem&lt;/a&gt; and the brute force approach to solving it is &lt;code&gt;O(n!)&lt;/code&gt; (factorial time) - as we must explore all possible routes.&lt;/li&gt;
&lt;li&gt;Exact algorithms that solve TSP optimally can work reasonably well for small inputs, however for larger (or unknown) inputs heuristic algorithms are popular.

&lt;ul&gt;
&lt;li&gt;Heuristic algorithms solve problems but produce solutions that are not guaranteed to be optimal. When we talk about TSP heuristic algorithms we mean algorithms that will produce an approximate solution.&lt;/li&gt;
&lt;li&gt;Heuristic approaches to solving TSP are typically faster than optimal approaches, meaning we can get an answer to TSP in a reasonable amount of time. If we choose the right algorithm(s), then an approximate solution can be acceptably close (and sometimes identical) to an optimal one.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Personally, I chose to solve a variation of TSP using two heuristic approaches that result in approximate solutions.

&lt;ul&gt;
&lt;li&gt;The variation is minor. I chose to solve TSP for a given start city (if none is provided, then I just solve starting at the first city in the given list).

&lt;ul&gt;
&lt;li&gt;The solution will be very similar for vanilla TSP, in fact slightly less complex as we do not care about final ordering of cities. In my implementations, I had to take extra care, especially when attempting to optimize a tour, to retain the specified start city.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The algorithms I implemented:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preorder Minimum Spanning Tree&lt;/strong&gt; (PMST) using Kruskal's algorithm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nearest Neighbour&lt;/strong&gt; (NN)

&lt;ul&gt;
&lt;li&gt;Optimized using repetition &amp;amp; sampling.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;In addition, I chose to optimize the resulting solutions (where appropriate) using 2-opt

&lt;ul&gt;
&lt;li&gt;2-opt is a local search algorithm often used to improve existing TSP solutions (that are not already optimal)&lt;/li&gt;
&lt;li&gt;Per Skiena, in &lt;a href="http://www.algorist.com/"&gt;The Algorithm Design Manual&lt;/a&gt;: "Two-opting a tour is a fast and effective way to improve any other heuristic." (p.535).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/2-opt"&gt;Here is the Wikipedia page for 2-opt&lt;/a&gt;. The algorithm as described is what I ended up using.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;I like the PMST approach because I had already covered minimum spanning tree (MST) in &lt;a href="https://dev.to/jjb/minimum-spanning-tree-kruskal-s-algorithm-19al"&gt;an earlier post&lt;/a&gt;, it also allowed me to brush up on &lt;a href="https://dev.to/jjb/union-find-disjoint-set-28c5"&gt;Union-Find&lt;/a&gt; which Kruskal's algorithm relies on (Kruskal's algorithm constructs an MST).&lt;/li&gt;
&lt;li&gt;The PMST approach has the benefit, as implemented, of being guaranteed to be no worse than 2x the optimal route (or tour). Meaning if an optimal tour is 20, at worse a PMST solution will be 40. 

&lt;ul&gt;
&lt;li&gt;An MST is a tree (list) of all the shortest edges in the graph that connect all vertices in the graph&lt;/li&gt;
&lt;li&gt;If we could rearrange an MST at no cost, we could rearrange it to be an optimal tour.&lt;/li&gt;
&lt;li&gt;As rearranging an MST does have a cost, we instead traverse it in a general way (preorder using DFS) to come up with an ordering that is "good enough" i.e an approximation.&lt;/li&gt;
&lt;li&gt;When rearranging an MST into a tour, the most we could traverse an edge is twice, but instead of doing this we instead "skip" to the next city.

&lt;ul&gt;
&lt;li&gt;This skip is a straight line &amp;amp; represents a single edge in our graph. &lt;/li&gt;
&lt;li&gt;Going via one edge in this way will always be the same or better than going via two edges. Why? because of triangle inequality.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Triangle inequality&lt;/strong&gt; states that for any triangle, the sum of the lengths of any two sides must be greater than or equal to the length of the remaining side.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;So if a subsection of our MST is a triangle with each side of our triangle being an edge and each point of our triangle being a vertex (&lt;code&gt;C--A--B&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;If we start at vertex &lt;code&gt;A&lt;/code&gt; and then visit &lt;code&gt;B&lt;/code&gt;, we will need to visit &lt;code&gt;C&lt;/code&gt; next (to complete our tour).&lt;/li&gt;
&lt;li&gt;To visit &lt;code&gt;C&lt;/code&gt; we can skip from &lt;code&gt;B&lt;/code&gt; to &lt;code&gt;C&lt;/code&gt; via a single edge &lt;code&gt;edge(B,C)&lt;/code&gt; or go via &lt;code&gt;A&lt;/code&gt; which will mean visiting two edges &lt;code&gt;edge(B,A) &amp;amp; edge(A,C)&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;We will always choose to visit &lt;code&gt;C&lt;/code&gt; via a single edge &lt;code&gt;edge(B,C)&lt;/code&gt; because: &lt;code&gt;edge(B,C) &amp;lt;= edge(B,A) + edge(A,C)&lt;/code&gt; - meaning &lt;code&gt;edge(B,C)&lt;/code&gt; (due to triangle inequality) can be shorter, but never longer.&lt;/li&gt;
&lt;li&gt;Therefore, preordering an MST means that in a worst case scenario our "skips" (going via one edge) will be as bad as going via two edges. Meaning at worst a preordering of vertices in an MST will produce a tour that is 2x the distance of an optimal tour (but often better than 2x).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NN is much simpler to reason about and the code is more concise, so I decided to provide an implementation for this algorithm as well.&lt;/li&gt;
&lt;li&gt;At a high level, this is how the chosen algorithms work:

&lt;ul&gt;
&lt;li&gt;PMST:

&lt;ul&gt;
&lt;li&gt;This approach first constructs an MST from the input graph of cities.&lt;/li&gt;
&lt;li&gt;This MST will have it's edges duplicated, to form an Eulerian graph.

&lt;ul&gt;
&lt;li&gt;We do this so that we can perform depth-first search (DFS) on our MST and preorder it's vertices (cities).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Once an MST is constructed we can perform DFS and the resulting order of vertices (cities) is our approximate solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NN:

&lt;ul&gt;
&lt;li&gt;This approach starts at any city &lt;code&gt;A&lt;/code&gt; and then proceeds to visit the nearest city to it &lt;code&gt;B&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The algorithm repeats this process (so will visit city &lt;code&gt;C&lt;/code&gt; that is closest to &lt;code&gt;B&lt;/code&gt; etc.) until all cities have been visited, then it will return to the origin city.&lt;/li&gt;
&lt;li&gt;We can optimize NN by executing it for every city in our list of cities, whilst keeping track of what the shortest tour produced was. We can call this repeated nearest neighbour.&lt;/li&gt;
&lt;li&gt;In the same way, we can take a subset (or sample) of cities at random and execute NN for each city in our subset, then return the shortest tour. We can call this sampled repeated nearest neighbour.&lt;/li&gt;
&lt;li&gt;Both repetition and sampling improve NN, but sampling is often &lt;em&gt;almost&lt;/em&gt; as good as repetition whilst being less expensive (quicker) - this is of course dependent on the sample size.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;2-opt:

&lt;ul&gt;
&lt;li&gt;2-opt's goal is to "uncross" any part of the route and see if preventing routes from crossing over each other's paths improves the solution.&lt;/li&gt;
&lt;li&gt;To do this 2-opt swaps 2 edges in a tour.&lt;/li&gt;
&lt;li&gt;To swap the 2 edges, 2-opt takes a tour and creates 3 subsections of it.&lt;/li&gt;
&lt;li&gt;The middle subsection is reversed (i.e 2 edges are swapped), with the leading and trailing subsections staying the same.&lt;/li&gt;
&lt;li&gt;If the resulting tour is better, we recurse and begin the 2-opt routine again (passing in our new, shorter, tour) - this way 2-opt will continue to optimize an already optimized tour, and will produce the most optimal tour it can.

&lt;ul&gt;
&lt;li&gt;Don't confuse this as meaning 2-opt can produce an optimal tour - most of the time it cannot, but it can improve tours.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If the tour is no better, or worse, than the original tour, then the window size is increased and the process is repeated.&lt;/li&gt;
&lt;li&gt;A bigger window means a larger middle subsection will get reversed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;So what are the time complexities of PMST, NN, &amp;amp; 2-opt?

&lt;ul&gt;
&lt;li&gt;PMST:

&lt;ul&gt;
&lt;li&gt;Time complexity for Kruskal's algorithm (used to construct our MST) is &lt;code&gt;O(e log v)&lt;/code&gt; where &lt;code&gt;e&lt;/code&gt; is the number of edges and &lt;code&gt;v&lt;/code&gt; is the number of vertices in the graph. Space is &lt;code&gt;O(v + e)&lt;/code&gt;. 

&lt;ul&gt;
&lt;li&gt;In our PMST solution of TSP we will double the edges, so space is actually worse, but constants are factored out in Big O.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Preorder traversal of our MST is &lt;code&gt;O(v + e)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Total time complexity of the PMST approach is &lt;code&gt;O(e log v)&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;My implementations take an adjacency matrix for city distances. I transform this matrix into an edge list. This incurs an &lt;code&gt;O(v^2)&lt;/code&gt; cost. I think this means that, as implemented, my solution is &lt;code&gt;O(e log v^2)&lt;/code&gt;. However, if supplied an edge/adjacency list as an input, this cost is not incurred.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NN:

&lt;ul&gt;
&lt;li&gt;NN's time complexity is &lt;code&gt;O(n^2)&lt;/code&gt; in the worst case. Space is &lt;code&gt;O(n)&lt;/code&gt;. Repeated NN is &lt;code&gt;O(n^3)&lt;/code&gt; and sampled NN is &lt;code&gt;O(n^k)&lt;/code&gt; where &lt;code&gt;k&lt;/code&gt; is the size of the sample.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;2-opt:

&lt;ul&gt;
&lt;li&gt;2-opt's complexity varies on the type of tour it is given:

&lt;ul&gt;
&lt;li&gt;In the average case, if starting with a tour made using a greedy algorithm (which our PMST &amp;amp; NN produce), the time complexity is &lt;code&gt;O(n)&lt;/code&gt;. If the tour is more randomly arrived at, then 2-opt's time complexity is &lt;code&gt;O(n log n)&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Extras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Held%E2%80%93Karp_algorithm"&gt;Held-Karp algorithm&lt;/a&gt; is a dynamic programming algorithm that solves the TSP optimally. It is &lt;code&gt;O(n^2 * 2^n)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/3-opt"&gt;3-opt&lt;/a&gt; is similar to 2-opt, but it swaps 3 edges instead of 2. It is  &lt;code&gt;O(n^3)&lt;/code&gt; for a single run, but can produce close to an optimal tour. 

&lt;ul&gt;
&lt;li&gt;Both 2 &amp;amp; 3-opt are a class of K-optimal tours.&lt;/li&gt;
&lt;li&gt;Per Skiena in &lt;a href="http://www.algorist.com/"&gt;The Algorithm Design Manual&lt;/a&gt;: K-optimal tours are "local refinements to an initially
arbitrary tour in the hopes of improving it. In particular, subsets of k edges
are deleted from the tour and the k remaining subchains rewired to form
a different tour with hopefully a better cost. A tour is k-optimal when no
subset of k edges can be deleted and rewired to reduce the cost of the tour." (p.535). 

&lt;ul&gt;
&lt;li&gt;When &lt;code&gt;K &amp;gt; 3&lt;/code&gt; the time complexity increases faster than the solution improves. So we often only deal with 2-opt or 3-opt in the context of TSP.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below you will find implementations of, &amp;amp; test cases for, preorder minimum spanning tree, variations of nearest neighbour, &amp;amp; 2-opt approximate solutions for the Traveling Salesman problem:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Dynamic Programming</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Sun, 31 May 2020 21:20:02 +0000</pubDate>
      <link>https://dev.to/jjb/dynamic-programming-3mal</link>
      <guid>https://dev.to/jjb/dynamic-programming-3mal</guid>
      <description>&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.educative.io/courses/grokking-dynamic-programming-patterns-for-coding-interviews/m2G1pAq0OO0"&gt;In-depth explanation with examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming"&gt;Wikipedia article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=xCbYmUPvc2Q"&gt;0/1 Knapsack problem video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=ASoaQq66foQ"&gt;Longest Common Subsequence (LCS) problem video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/williamfiset/Algorithms/blob/master/src/main/java/com/williamfiset/algorithms/dp/LongestCommonSubsequence.java"&gt;Bottom-up LCS implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bephrem1/backtobackswe/blob/master/Dynamic%20Programming,%20Recursion,%20&amp;amp;%20Backtracking/LongestCommonSubsequence/TopDown.java"&gt;Top-down LCS implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bephrem1/backtobackswe/blob/master/Dynamic%20Programming%2C%20Recursion%2C%20%26%20Backtracking/Knapsack01/TopDownNoMemoization.java"&gt;Top-down 0/1 Knapsack implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/williamfiset/Algorithms/blob/master/src/main/java/com/williamfiset/algorithms/dp/Knapsack_01.java"&gt;Bottom-up 0/1 Knapsack implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic programming is a process by which a larger problem is reduced to sub-problems. &lt;/li&gt;
&lt;li&gt;These sub-problems are easier to reason about, easier to solve individually, and are typically decision problems. &lt;/li&gt;
&lt;li&gt;By solving these sub-problems, dynamic programming enables  us to build up an answer to the larger, more complex, problem. &lt;/li&gt;
&lt;li&gt;If a problem can be solved optimally in this way then the problem is considered to have an optimal substructure. 

&lt;ul&gt;
&lt;li&gt;Optimal substructure just means that a problem has an optimal solution that has been constructed from optimal solutions of it's sub-problems.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Dynamic programming solutions are usually either &lt;strong&gt;top-down&lt;/strong&gt; or &lt;strong&gt;bottom-up&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Top-down means we start from our input(s) and work downwards to our base-case using recursion (remember recursive functions have a base-case that determines when the recursion should end, similar to an exit condition in a while loop). &lt;/li&gt;
&lt;li&gt;Bottom-up means we start from the base-case and work upwards.

&lt;ul&gt;
&lt;li&gt;Bottom-up is recursion free and thus will avoid building up a call stack of &lt;code&gt;O(n)&lt;/code&gt; size. This means bottom-up approaches can be more memory efficient than their top-down counterparts. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Top-down solutions use recursion and memoization to solve the larger problem, whereas bottom-up solutions will use a nested for-loop to build a solution matrix/table before contructing the answer from the matrix.

&lt;ul&gt;
&lt;li&gt;Memoization is sort of like &lt;em&gt;caching&lt;/em&gt;. We remember the results of a computation so we don't have to recompute the same thing over and over. We instead check the "cache" and see if we have already done the work previously. &lt;a href="https://www.interviewcake.com/concept/java/memoization"&gt;Here's a good article on memoization.&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A sub-problem solution table, or matrix, is a matrix with each coordinate (&lt;code&gt;x,y&lt;/code&gt;) containing the answer to a sub-problem (&lt;code&gt;x,y&lt;/code&gt; axis are representations of the problem inputs). &lt;/li&gt;
&lt;li&gt;For example, &lt;code&gt;x&lt;/code&gt; might represent a weight input, and &lt;code&gt;y&lt;/code&gt; might represent a &lt;code&gt;cost&lt;/code&gt; input. Given a weight of &lt;code&gt;1&lt;/code&gt; and a cost of &lt;code&gt;$3&lt;/code&gt; we can find out in our matrix what the optimal solution is for those inputs by going to the &lt;code&gt;x,y&lt;/code&gt; coordinates &lt;code&gt;1,3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Top-down dynamic programming solutions memoize the solutions to sub-problems to avoid duplicated work. &lt;/li&gt;
&lt;li&gt;Bottom-up solutions merely keep a solution matrix/table in memory, but only use it for constructing the solution - meaning technically there is no memoization, as the same sub-problem does not get solved more than once. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A famous dynamic programming problem is the 0/1 Knapsack problem&lt;/li&gt;
&lt;li&gt;The 0/1 Knapsack problem statement is:

&lt;ul&gt;
&lt;li&gt;Given a knapsack &amp;amp; a set of items (each item has a weight and value) determine the items to put in your knapsack. The total weight of the knapsack must be less than or equal to a given limit, and the total value should be as large as possible.&lt;/li&gt;
&lt;li&gt;The items cannot be split/divided. Which is where the &lt;code&gt;0/1&lt;/code&gt; comes from - we either take an item or leave it.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The following is an overview of solutions to 0/1 Knapsack (at the conclusion of this post you will find actual code for both top-down and bottom-up solutions): &lt;/li&gt;
&lt;li&gt;The naive, brute force, solution to 0/1 Knapsack is to try all possible combinations of items, keeping track of which subset yields the greatest value whilst being under the weight limit. 

&lt;ul&gt;
&lt;li&gt;This approach is exponential &lt;code&gt;O(2^n)&lt;/code&gt;, with space being &lt;code&gt;O(n)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The algorithm would be something like:

&lt;ul&gt;
&lt;li&gt;Define a recursive function (e.g &lt;code&gt;solveKnapsack(int[] values, int[] weights, int weightLimit, int index)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Define a base-case at the start of our function that will ensure our index and weight limit are not out of bounds.&lt;/li&gt;
&lt;li&gt;For each item &lt;code&gt;i&lt;/code&gt; (i.e value of &lt;code&gt;i&lt;/code&gt; is &lt;code&gt;values[i]&lt;/code&gt;, weight of &lt;code&gt;i&lt;/code&gt; is &lt;code&gt;weight[i]&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Compute a value &lt;code&gt;v1&lt;/code&gt; which &lt;strong&gt;includes&lt;/strong&gt; item &lt;code&gt;i&lt;/code&gt; if it's weight is lower than our weight limit, deduct &lt;code&gt;i&lt;/code&gt;'s weight from our limit &amp;amp; then recursively process the remaining items.&lt;/li&gt;
&lt;li&gt;Otherwise, if &lt;code&gt;i&lt;/code&gt; has a weight greater than our limit, compute a value &lt;code&gt;v2&lt;/code&gt; which &lt;strong&gt;exludes&lt;/strong&gt; item &lt;code&gt;i&lt;/code&gt; and then recursively process the remaining items.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;At the end of our recursive function, return the maximum between &lt;code&gt;v1&lt;/code&gt; and &lt;code&gt;v2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If our naive approach is written recursively similar to described, then we can see that this approach is top-down - it is working from our inputs downwards to a base-case. &lt;/li&gt;
&lt;li&gt;Each call to &lt;code&gt;solveKnapsack&lt;/code&gt; in our naive solution is solving a sub-problem: do we include or exlude item &lt;code&gt;i&lt;/code&gt;? And whatever the answer, what is the value (&lt;code&gt;v1&lt;/code&gt; or &lt;code&gt;v2&lt;/code&gt;) of that decision?&lt;/li&gt;
&lt;li&gt;We can add an extra parameter (representing a table or matrix) to our function that could be used to memoize the results of these sub-problems. This will help to avoid duplicated work (assuming we also add a check that will return the memoized value/sub-problem solution, if it has already been solved)&lt;/li&gt;
&lt;li&gt;A bottom-up approach merely removes recursion from our previous solution and builds up the matrix at the start of the function. We can then use the matrix to determine things like: what is the maximum value? what items were selected? (via backtracking).&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time &amp;amp; space complexities for the top-down and bottom-up solutions are &lt;code&gt;O(nm)&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is the number of items and &lt;code&gt;m&lt;/code&gt; is the weight limit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another famous problem that can be solved with dynamic programming is &lt;strong&gt;Longest Common Subsequence&lt;/strong&gt; (LCS). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;LCS problem statement is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given two strings &lt;code&gt;inputA&lt;/code&gt; and &lt;code&gt;inputB&lt;/code&gt;, return the length of their longest common subsequence.&lt;/li&gt;
&lt;li&gt;Other variations might also ask you to return the LCS string itself. In my implementations I return the length, but also print the LCS before returning. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;So what exactly is a subsequence?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A subsequence of a string &lt;code&gt;A&lt;/code&gt; is a new string &lt;code&gt;B&lt;/code&gt; that has some of the characters from &lt;code&gt;A&lt;/code&gt; deleted, without changing the relative order of the remaining characters. 

&lt;ul&gt;
&lt;li&gt;This is unlike a substring, which is simply a sub-section of another string. &lt;/li&gt;
&lt;li&gt;For example: given &lt;code&gt;A = "abcdefg"&lt;/code&gt; a subsequence &lt;code&gt;B&lt;/code&gt; could be &lt;code&gt;"acdeg"&lt;/code&gt; or &lt;code&gt;"ag"&lt;/code&gt; or &lt;code&gt;"abd"&lt;/code&gt;. Notice how &lt;code&gt;B&lt;/code&gt;'s characters all exist in &lt;code&gt;A&lt;/code&gt;? And how each character's &lt;em&gt;relative&lt;/em&gt; position is unchanged? &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"acb"&lt;/code&gt; &amp;amp; &lt;code&gt;"dac"&lt;/code&gt; would represent a change in the relative order and so are examples of invalid subsequences of &lt;code&gt;A&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Further, we can say that if two strings share a subsequence it is a common subsequence. An example of a common subsequence: Given two strings &lt;code&gt;A&lt;/code&gt; &amp;amp; &lt;code&gt;B&lt;/code&gt;(&lt;code&gt;A = "hello", B = "below"&lt;/code&gt;) a common subsequnce &lt;code&gt;C&lt;/code&gt; of the two is &lt;code&gt;C = "el"&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;The solutions to LCS are strikingly similar to the ones for 0/1 Knapsack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The naive approach, again, is brute force and checks every possible subsequence in &lt;code&gt;inputA[0..n]&lt;/code&gt; and &lt;code&gt;inputB[0..m]&lt;/code&gt;. The longest subsequence that exists in both inputs will be returned.

&lt;ul&gt;
&lt;li&gt;This approach is &lt;code&gt;O(n * 2^m)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;But what decisions does our naive approach make? How is it finding the subsequences?

&lt;ul&gt;
&lt;li&gt;For each recursive call to &lt;code&gt;solveLCS(string inputA, string inputB)&lt;/code&gt;, if both &lt;code&gt;inputA&lt;/code&gt; &amp;amp; &lt;code&gt;inputB&lt;/code&gt; end with the same character then we remove the trailing character from each and recursively call &lt;code&gt;solveLCS(inputA[0..n-1], inputB[0..m-1])&lt;/code&gt; and return the result.

&lt;ul&gt;
&lt;li&gt;Why? Because if they end with the same character, that means we have found a subsequence - we remove that character and process the rest of each string to determine how long the longest subsequence is.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If our inputs do not have the same last character, then we have yet to identify a subsequence so we must remove a trailing character from one of the inputs and recursively call &lt;code&gt;solveLCS()&lt;/code&gt;, returning the result. 

&lt;ul&gt;
&lt;li&gt;We do this for &lt;em&gt;both&lt;/em&gt; &lt;code&gt;inputA&lt;/code&gt; and &lt;code&gt;inputB&lt;/code&gt; (&lt;code&gt;(inputA[0..n-1], inputB[0..m])&lt;/code&gt; &amp;amp; &lt;code&gt;(inputA[0..n], inputB[0..m-1])&lt;/code&gt;), after computing the LCS of both we return the &lt;em&gt;larger&lt;/em&gt; of the two values. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The base-case for our naive recursive algorithm checks if &lt;code&gt;inputA&lt;/code&gt; or &lt;code&gt;inputB&lt;/code&gt; are empty strings (as we will be removing characters from each during the recursion).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Like 0/1 Knapsack, to transform the naive recursive solution into a dynamic top-down solution all we need to do is add an additional data structure as a parameter. This parameter will represent our table/matrix and will be used to memoize each sub-problem's solution. We effectively cache each decision made in the recursive routine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Again, like with 0/1 Knapsack, a bottom-up solution will not use recursion and instead, upfront, build the solution matrix using a nested for-loop. From the resulting matrix we can deduce solutions to: what is the longest common subsequence? What characters are in that subsequence?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time &amp;amp; space complexities for the top-down and bottom-up LCS solutions are &lt;code&gt;O(nm)&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is the number of characters in &lt;code&gt;inputA&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; is the number of characters in &lt;code&gt;inputB&lt;/code&gt;. The top-down solution, due to recursion, is technically &lt;code&gt;O(nm + n)&lt;/code&gt; - but asymptotically we don't factor in the extra cost (because it is constant). &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, you will notice that both 0/1 Knapsack and LCS problems are solvable in exponential time when approached naively. Dynamic programming not only gives us a blueprint for solving both, but enables us to reduce the running time for both these problems to polynomial running time (specifically &lt;code&gt;O(nm)&lt;/code&gt;). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polynomial running time is simply a category of running times. Formally, it is any running time that is &lt;code&gt;O(n^k)&lt;/code&gt; where &lt;code&gt;k&lt;/code&gt; is non-negative. Polynomial running time is &lt;em&gt;much&lt;/em&gt; better than exponential running time.  &lt;a href="https://stackoverflow.com/a/34517541/3574076"&gt;Here is a good comparison of various time complexities and their rates of growth&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below are top-down &amp;amp; bottom-up solutions to LCS &amp;amp; 0/1 Knapsack problems, with test cases:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Fenwick Tree (Binary Indexed Tree)</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Fri, 15 May 2020 23:48:55 +0000</pubDate>
      <link>https://dev.to/jjb/fenwick-tree-binary-indexed-tree-3e7l</link>
      <guid>https://dev.to/jjb/fenwick-tree-binary-indexed-tree-3e7l</guid>
      <description>&lt;p&gt;To understand Fenwick trees you will need to first understand binary representation of numbers and basic bit manipulation, &lt;a href="https://dev.to/jjb/part-11-learning-binary-bit-manipulation-3a7n"&gt;a previous post of mine covers these topics&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=uSFzHCZ4E-8"&gt;Video overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=CWDQJGaN1gY"&gt;Video explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/williamfiset/Algorithms/blob/master/src/main/java/com/williamfiset/algorithms/datastructures/fenwicktree/FenwickTreeRangeQueryPointUpdate.java"&gt;Implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Fenwick tree is a data structure that can efficiently calculate prefix sums for a range of numbers, whilst also supporting updates efficiently.

&lt;ul&gt;
&lt;li&gt;A prefix sum is essentially a running total of a range of numbers. The prefix sums of &lt;code&gt;sourceArray = [1,2,3,4,5]&lt;/code&gt; are &lt;code&gt;prefixSumArray = [1,3,6,10,15]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Arrays, like Fenwick trees, can be used for prefix sums. &lt;/li&gt;
&lt;li&gt;Using the previous example: calculating the prefix sum at &lt;code&gt;prefixSumArray[i]&lt;/code&gt; is an &lt;code&gt;O(1)&lt;/code&gt; operation. &lt;/li&gt;
&lt;li&gt;Updating an element at &lt;code&gt;sourceArray[i]&lt;/code&gt; means we also need to update our prefix sum array. This is an expensive operation that takes &lt;code&gt;O(n)&lt;/code&gt; - because we need to update &lt;code&gt;n&lt;/code&gt; prefixes in &lt;code&gt;prefixSumArray&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;To construct a prefix sum array takes &lt;code&gt;O(n)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;By contrast, a Fenwick tree also takes &lt;code&gt;O(n)&lt;/code&gt; for construction but is &lt;code&gt;O(log n)&lt;/code&gt; for both updates &amp;amp; prefix sum operations.&lt;/li&gt;
&lt;li&gt;Space complexity of a Fenwick tree is &lt;code&gt;O(n)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A Fenwick tree is an array that stores, at each index, prefix sums of &lt;code&gt;n&lt;/code&gt; elements from a source array

&lt;ul&gt;
&lt;li&gt;This is different to a prefix array because each index has a relation to other indices. Because of this, at each index we do not store the prefix sum of all elements that precede it - instead we store the prefix sum of all it's child indices. &lt;/li&gt;
&lt;li&gt;This relationship between indices means that at each index in a Fenwick tree we store data that is the sum of &lt;code&gt;n&lt;/code&gt; indices, but not necessarily the sum of all the indices up to and including &lt;code&gt;i&lt;/code&gt; (which is what a prefix array does).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A Fenwick tree is actually not a tree structure, instead the tree is stored as an array that represents a tree.

&lt;ul&gt;
&lt;li&gt;Index 0 of the array is the virtual root node of the tree and is not used for data (prefixes)&lt;/li&gt;
&lt;li&gt;Half of the elements have a range of responsibility for 1 element&lt;/li&gt;
&lt;li&gt;A quarter of elements have responsibility for 2 elements&lt;/li&gt;
&lt;li&gt;An eighth of elements have a responsibility for 4 elements&lt;/li&gt;
&lt;li&gt;A sixteenth of the elements have a responsibility for 8 elements&lt;/li&gt;
&lt;li&gt;And so on...&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Range of responsibility, in this context, means that the elements contain a prefix sum for the range of elements they are responsible for. 

&lt;ul&gt;
&lt;li&gt;This means, unlike prefix arrays, we do not need to check every element in a range of indices to calculate a prefix sum.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A Fenwick tree does this dividing/assigning of range of responsibility based on the binary representation of the indices of the array. This works like so:

&lt;ul&gt;
&lt;li&gt;If the furthest right bit of &lt;code&gt;i&lt;/code&gt; is set to &lt;code&gt;1&lt;/code&gt; (1) then the same data from the source array is stored at the same position in the Fenwick tree array. These are the "half of elements" and have a range of responsibility of 1 - as they contain the exact values from the source array.&lt;/li&gt;
&lt;li&gt;If the first bit of &lt;code&gt;i&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt; (0) but the second bit is set to &lt;code&gt;1&lt;/code&gt; (2) then the range of responsibility is 2. These are the "quarter of elements". Again, the data is stored at the same index in the Fenwick tree array as it was in the source array - however this time the data will be the sum of &lt;code&gt;sourceArray[i] + sourceArray[i - 1]&lt;/code&gt; (indices of the "quarter of elements" are parents of the "half of elements" indices).&lt;/li&gt;
&lt;li&gt;If the first two bits of &lt;code&gt;i&lt;/code&gt; are &lt;code&gt;0&lt;/code&gt; but the third bit is set to &lt;code&gt;1&lt;/code&gt; (4) then the range of responsibility is 4. These are the "eighth of elements". These elements are the parents of the "quarter of elements" and grandparents of the "half of elements". The sum of the previous 3 elements, and the current element (&lt;code&gt;sourceArray[i]&lt;/code&gt;), are stored in the Fenwick tree array at the current index. &lt;/li&gt;
&lt;li&gt;This process continues until all indices are filled with sums of elements from the source array. The Fenwick tree will now contain elements that are all prefixes across a certain range of elements (1,2,4,8 etc.).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;To calculate a prefix sum using a Fenwick tree, if we are given an index &lt;code&gt;i&lt;/code&gt; we simply loop &lt;code&gt;while (i &amp;gt; 0)&lt;/code&gt; (0 is our root node with no data in it) and inside the loop add the current element at &lt;code&gt;i&lt;/code&gt; to a running sum &lt;code&gt;sum += tree[i]&lt;/code&gt;. Then we decrement &lt;code&gt;i&lt;/code&gt; by flipping it's last set bit to &lt;code&gt;0&lt;/code&gt;. The process is repeated until all of &lt;code&gt;i&lt;/code&gt;'s bits are flipped to &lt;code&gt;0&lt;/code&gt;. 

&lt;ul&gt;
&lt;li&gt;Flipping last set bits like this, means we traverse up the tree to &lt;code&gt;i&lt;/code&gt;'s parent &amp;amp; any ancestor nodes (indices). As indices can have a range of responsibility larger than one, we do not have to visit &lt;em&gt;all&lt;/em&gt; the elements in a range to calculate the prefix sum. Just &lt;code&gt;i&lt;/code&gt; and it's ancestors in the tree.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;To increase or decrease the value in a Fenwick tree stored at an index &lt;code&gt;i&lt;/code&gt; by an integer &lt;code&gt;x&lt;/code&gt;, the logic is very similar to prefix sum:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;while(i &amp;lt; tree.Length)&lt;/code&gt; we add &lt;code&gt;x&lt;/code&gt; to the current index &lt;code&gt;tree[i] += x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After updating the current index, we need to update all of &lt;code&gt;i&lt;/code&gt;'s ancestors. &lt;/li&gt;
&lt;li&gt;To do this we add the last set bit to of &lt;code&gt;i&lt;/code&gt; to itself (so &lt;code&gt;0010&lt;/code&gt; (2) becomes &lt;code&gt;0100&lt;/code&gt; (4)). &lt;/li&gt;
&lt;li&gt;We continue adding &lt;code&gt;x&lt;/code&gt; to &lt;code&gt;tree[i]&lt;/code&gt; and incrementing &lt;code&gt;i&lt;/code&gt; whilst &lt;code&gt;i&lt;/code&gt; is smaller than our tree length (to prevent going out of bounds).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The logic in our add operation (just described), of incrementing &lt;code&gt;i&lt;/code&gt; by it's last set bit (which leaves us with an index representing &lt;code&gt;i&lt;/code&gt;'s parent), is used when constructing a Fenwick tree in &lt;code&gt;O(n)&lt;/code&gt;. We loop over every element in the source array, find &lt;code&gt;i&lt;/code&gt;'s parent and populate data in our tree. This helps to effectively partition our Fenwick tree array into indices with ranges of responsibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below you will find a Fenwick tree implementation with test cases. There are other basic operations a Fenwick tree can support by reusing the prefix sum or add operations, some of these have been implemented below:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>String Searching Using Rabin-Karp</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Tue, 05 May 2020 03:39:41 +0000</pubDate>
      <link>https://dev.to/jjb/detecting-plagiarism-string-searching-using-rabin-karp-5gf2</link>
      <guid>https://dev.to/jjb/detecting-plagiarism-string-searching-using-rabin-karp-5gf2</guid>
      <description>&lt;p&gt;The Rabin-Karp algorithm is a string-searching algorithm that uses hashing to find a pattern (or patterns) in an input string.&lt;/p&gt;

&lt;p&gt;It is not the quickest algorithm for finding a single pattern, however a small tweak can allow the algorithm to perform well for multiple patterns. Using Rabin-Karp to search for multiple patterns could come in handy for things like detecting common words, sentences, or characters between documents or even source code.&lt;/p&gt;

&lt;p&gt;In this post I will detail resources for learning about Rabin-Karp, go over it's key features, &amp;amp; provide a complete + efficient implementation of the algorithm (with test cases).&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm"&gt;Rabin-Karp Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/BRO7mVIFt08?list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&amp;amp;t=1729"&gt;MIT Video Explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=BfUejqd07yo"&gt;Rolling Hash Video Explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ellard.org/dan/www/Q-97/HTML/root/node43.html"&gt;Article Explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://algs4.cs.princeton.edu/53substring/RabinKarp.java.html"&gt;Implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Takeaways:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Aside from a tricky &lt;strong&gt;rolling-hash&lt;/strong&gt;, the algorithm is simple compared to other string-searching algorithms.&lt;/li&gt;
&lt;li&gt;The algorithm is as follows:

&lt;ul&gt;
&lt;li&gt;Accept an input &lt;code&gt;i&lt;/code&gt; and a pattern &lt;code&gt;p&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Define a variable &lt;code&gt;n&lt;/code&gt; to be the length of &lt;code&gt;i&lt;/code&gt; and a variable &lt;code&gt;m&lt;/code&gt; to be the length of &lt;code&gt;p&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a hash of pattern &lt;code&gt;p&lt;/code&gt; (&lt;code&gt;hashP&lt;/code&gt;) and a hash of length &lt;code&gt;m&lt;/code&gt; of input &lt;code&gt;i&lt;/code&gt; (&lt;code&gt;hashI&lt;/code&gt;).

&lt;ul&gt;
&lt;li&gt;I.e for an input &lt;code&gt;i = "abcde"&lt;/code&gt; and a pattern length &lt;code&gt;m&lt;/code&gt; of 2, &lt;code&gt;hashI&lt;/code&gt; would be a hash of the substring &lt;code&gt;"ab"&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;hashP == hashI&lt;/code&gt; then we have possibly found pattern &lt;code&gt;p&lt;/code&gt; at the start of input &lt;code&gt;i&lt;/code&gt;. Check each character of the substring representing &lt;code&gt;hashI&lt;/code&gt; with our pattern &lt;code&gt;p&lt;/code&gt; to be sure (call this function &lt;code&gt;CheckEqual()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Otherwise iterate from pattern length &lt;code&gt;m&lt;/code&gt; to input length &lt;code&gt;n&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For each iteration recalculate the hash &lt;code&gt;hashI&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;We are sliding a window across our input&lt;/li&gt;
&lt;li&gt;Window is of size &lt;code&gt;m&lt;/code&gt; (pattern length)&lt;/li&gt;
&lt;li&gt;This means for each iteration we are removing a leading character from our hash and adding a trailing character&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;i = "abcde"&lt;/code&gt;, &lt;code&gt;m = 2&lt;/code&gt;, and &lt;code&gt;hashI&lt;/code&gt; represents &lt;code&gt;"ab"&lt;/code&gt; - then our first iteration would remove &lt;code&gt;"a"&lt;/code&gt; from &lt;code&gt;hashI&lt;/code&gt; and add &lt;code&gt;"c"&lt;/code&gt;. Meaning &lt;code&gt;hashI&lt;/code&gt; now represents &lt;code&gt;"bc"&lt;/code&gt;. This part of the operation is done in constant time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;After rehashing, check if &lt;code&gt;hashP == hashI&lt;/code&gt;. If they are the same, run our character equality check &lt;code&gt;CheckEqual()&lt;/code&gt; to be certain.&lt;/li&gt;
&lt;li&gt;Explore all of &lt;code&gt;i&lt;/code&gt; until we have found our pattern or no pattern exists in &lt;code&gt;i&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A rolling hash is a hash function where the input is hashed in a &lt;strong&gt;sliding window&lt;/strong&gt;. As the window moves through the input the hash is updated quicker than rehashing all the characters in the new window - as the previous window and the current window share characters. 

&lt;ul&gt;
&lt;li&gt;E.g if our input is &lt;code&gt;"abcde"&lt;/code&gt; and our window size is 3. We first hash &lt;code&gt;"abc"&lt;/code&gt; then slide our window and next hash &lt;code&gt;"bcd"&lt;/code&gt; - a rolling hash takes advantage of the fact that &lt;code&gt;"bc"&lt;/code&gt; was already hashed. Instead of hashing &lt;code&gt;"bc"&lt;/code&gt; again a rolling hash removes &lt;code&gt;"a"&lt;/code&gt; and appends to the hash of &lt;code&gt;"bc"&lt;/code&gt; the hash of &lt;code&gt;"c"&lt;/code&gt;. This means a hash for &lt;code&gt;"bc&lt;/code&gt;" was only calculated once for two hashes.&lt;/li&gt;
&lt;li&gt;Extrapolated over larger inputs, and more times, a rolling hash can be very efficient. It's the reason Rabin-Karp is reasonably fast at string-searching.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Rabin-Karp's rolling hash is calculated modulo a large prime number. This means hash values are also relatively prime and the distribution of the hash values are more uniform.

&lt;ul&gt;
&lt;li&gt;Choosing a large prime helps us avoid false positives - where two hashes are the same but the values they represent are not.&lt;/li&gt;
&lt;li&gt;Choosing a random prime means we can guard against the worst case running time, as no specific inputs will affect the running time predictably.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The rolling hash is often computed multiplied by a relatively prime Base/Radix. This value should be at least as large as the character set. For my implementation I used 256 - as this is the number of ASCII characters.&lt;/li&gt;
&lt;li&gt;A common rolling hash for Rabin-Karp is: &lt;code&gt;S[i]*R^m-i % Q&lt;/code&gt;. Where &lt;code&gt;S&lt;/code&gt; is our input string, &lt;code&gt;i&lt;/code&gt; is the position (in a loop/iteration), &lt;code&gt;R&lt;/code&gt; is the radix/base, &lt;code&gt;m&lt;/code&gt; is the pattern length, and &lt;code&gt;Q&lt;/code&gt; is the prime. 

&lt;ul&gt;
&lt;li&gt;Using &lt;a href="https://en.wikipedia.org/wiki/Horner%27s_method"&gt;Horner's Method&lt;/a&gt; this can be simplified in code to:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight csharp"&gt;&lt;code&gt;        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;patternLength&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;patternLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ascii&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="c1"&gt;// Assume Base/Prime are already defined&lt;/span&gt;
                &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ascii&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="n"&gt;Prime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Time complexity of Rabin-Karp is linear (specifically, amortized &lt;code&gt;O(n + m)&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is input length and &lt;code&gt;m&lt;/code&gt; is pattern length).&lt;/li&gt;
&lt;li&gt;Brute forced approaches, and worst case Rabin-Karp (more likely with smaller, non-random primes, and/or bad rolling hash), are &lt;code&gt;O(n * m)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Space is &lt;code&gt;O(1)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We can modify Rabin-Karp with a &lt;a href="https://llimllib.github.io/bloomfilter-tutorial/"&gt;Bloom Filter&lt;/a&gt; or simply a hash set to search for multiple patterns. &lt;/li&gt;
&lt;li&gt;In my implementations I return the index (aka offset) the pattern starts at in the input. You could easily modify either the single or multiple pattern implementations to do other things (like count occurrences of patterns).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below are Rabin-Karp implementations for single &amp;amp; multiple patterns (of the same size). The implementations assume ASCII input and will work for inputs up to a reasonably large size. The rolling hash uses a relatively large random prime to guard against poor running times:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Sliding Window Technique</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Mon, 20 Apr 2020 03:10:34 +0000</pubDate>
      <link>https://dev.to/jjb/sliding-window-technique-dj7</link>
      <guid>https://dev.to/jjb/sliding-window-technique-dj7</guid>
      <description>&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=MK-NZ4hN7rs"&gt;Video explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/permutation-in-string"&gt;Leetcode problem&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The sliding window technique is where we use two pointers on a collection. We say that one pointer represents the start of the window and the other the end of the window. The space/elements between the two pointers is the window size.&lt;/li&gt;
&lt;li&gt;A sliding window can be of fixed length or it can be variable length (meaning the window expands/contracts dynamically).

&lt;ul&gt;
&lt;li&gt;Fixed length is often easier to grasp/think about. Both pointers, say &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt;, in a loop are incremented by the same number each time our max window size is reached.&lt;/li&gt;
&lt;li&gt;Variable length is where &lt;code&gt;i&lt;/code&gt; or &lt;code&gt;j&lt;/code&gt; change at a different pace to each other. Often questions requiring this technique don't provide a window size, but ask for the largest/smallest possible window given some constraints.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Here are some questions we can use the sliding window technique on:

&lt;ul&gt;
&lt;li&gt;In an array of &lt;code&gt;n&lt;/code&gt; integers, find a contiguous &lt;code&gt;k&lt;/code&gt; length subarray that has the largest value when it's elements are summed.

&lt;ul&gt;
&lt;li&gt;We can use two pointers here and our window would be of size &lt;code&gt;k&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What is the size of the minimum subarray that when summed will equal a target sum?

&lt;ul&gt;
&lt;li&gt;We can use two pointers here, but because we want the &lt;em&gt;minimum&lt;/em&gt; length subarray (i.e the question is asking how big/small the window is) the window can't be of fixed length.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What is the largest subarray of &lt;code&gt;k&lt;/code&gt; distinct characters?

&lt;ul&gt;
&lt;li&gt;We can use two pointers here. This will again be a variable length window, as we are being asked what the size of the window is (largest subarray). We will also need to use an auxiliary data structure to keep track of how many distinct characters are in a given subarray.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A less obvious question where sliding window would come in handy:

&lt;ul&gt;
&lt;li&gt;Given two strings &lt;code&gt;inputA&lt;/code&gt; &amp;amp; &lt;code&gt;inputB&lt;/code&gt;, determine if any permutation of &lt;code&gt;inputA&lt;/code&gt; is a substring of &lt;code&gt;inputB&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;Here we can use two pointers and the window will be of fixed size/won't ever grow larger than the length of &lt;code&gt;inputA&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below are solutions to all the problems mentioned. I have annotated the source code with time &amp;amp; space complexities for each solution:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Minimum Spanning Tree (Kruskal's Algorithm)</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Sun, 12 Apr 2020 00:33:40 +0000</pubDate>
      <link>https://dev.to/jjb/minimum-spanning-tree-kruskal-s-algorithm-19al</link>
      <guid>https://dev.to/jjb/minimum-spanning-tree-kruskal-s-algorithm-19al</guid>
      <description>&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;p&gt;This post requires knowledge of graphs and union-find (covered in earlier posts).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=fAuF0EuZVCk"&gt;Kruskal's algorithm video explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=JZBQLXgSGfs&amp;amp;list=PLDV1Zeh2NRsBI1C-mR6ZhHTyfoEJWlxvq"&gt;Another video explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mission-peace/interview/blob/master/src/com/interview/graph/KruskalMST.java"&gt;OO implementation of Kruskal's&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Minimum_spanning_tree"&gt;Wikipedia article on Minimum Spanning Tree&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Minimum Spanning Tree (MST) is a subset of edges of an undirected, connected, weighted graph. 

&lt;ul&gt;
&lt;li&gt;This means a MST connects all vertices together in a path that has the smallest total edge weight.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;One algorithm for finding the MST of a graph is &lt;strong&gt;Kruskal's Algorithm&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Kruskal's algorithm is a &lt;strong&gt;greedy algorithm&lt;/strong&gt; - this means it will make locally optimum choices, with an intent of finding the overall optimal solution.&lt;/li&gt;
&lt;li&gt;Kruskal's algorithm relies on the &lt;strong&gt;union-find&lt;/strong&gt; data structure.

&lt;ul&gt;
&lt;li&gt;First the algorithm sorts the graph's edges in ascending order (by weight). &lt;/li&gt;
&lt;li&gt;Then for every edge, if it's vertices have different root vertices (determined by union-find's &lt;code&gt;Find()&lt;/code&gt;), it will add the edge to a list &amp;amp; &lt;code&gt;Union()&lt;/code&gt; it's vertices within the union-find data structure.&lt;/li&gt;
&lt;li&gt;If roots are the same, it will skip the edge.&lt;/li&gt;
&lt;li&gt;The final list represents the MST of the graph.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Another common algorithm for finding the MST of a graph is &lt;a href="https://en.wikipedia.org/wiki/Prim%27s_algorithm"&gt;Prim's Algorithm&lt;/a&gt;. Commonly, Prim's uses a heap or priority queue in it's implementation.&lt;/li&gt;
&lt;li&gt;Time complexity for Kruskal's algorithm is &lt;code&gt;O(e log v)&lt;/code&gt; where &lt;code&gt;e&lt;/code&gt; is the number of edges and &lt;code&gt;v&lt;/code&gt; is the number of vertices in the graph. Space is &lt;code&gt;O(e + v)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is my implementation of Kruskal's algorithm:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Union-find (Disjoint-set)</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Sun, 05 Apr 2020 23:28:01 +0000</pubDate>
      <link>https://dev.to/jjb/union-find-disjoint-set-28c5</link>
      <guid>https://dev.to/jjb/union-find-disjoint-set-28c5</guid>
      <description>&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLDV1Zeh2NRsBI1C-mR6ZhHTyfoEJWlxvq"&gt;Youtube playlist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=ID00PMy0-vE"&gt;Video explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://algs4.cs.princeton.edu/15uf/"&gt;Princeton explanation &amp;amp; implementations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure"&gt;Wikipedia article&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The union-find data structure (also known as disjoint-set) keeps track of elements that are partitioned into disjoint subsets (also called components).&lt;/li&gt;
&lt;li&gt;When elements are initially added to union-find, they are all considered members of their own component. That means if we create a union-find with 3 elements it will also contain 3 components (each component being a single element). This is achieved by having each element specify itself as its parent (self-referencing).&lt;/li&gt;
&lt;li&gt;Union-find has three main operations: &lt;code&gt;MakeSet()&lt;/code&gt;, &lt;code&gt;Union()&lt;/code&gt;, &amp;amp; &lt;code&gt;Find()&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MakeSet()&lt;/code&gt; takes an element, adds it to the underlying collection/tree, gives it either a &lt;code&gt;rank&lt;/code&gt; of 0 or &lt;code&gt;size&lt;/code&gt; of 1 (explained later on), and specifies a parent pointer to itself (which creates a new component).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Find()&lt;/code&gt; takes an element &lt;code&gt;x&lt;/code&gt; and traverses it's parent chain. &lt;code&gt;Find()&lt;/code&gt; tells us what component &lt;code&gt;x&lt;/code&gt; is in by finding the root element of that component. If two elements have the same root, they are in the same component.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Union()&lt;/code&gt; takes two elements &lt;code&gt;x &amp;amp; y&lt;/code&gt; and merges the components they belong to together. &lt;code&gt;Union()&lt;/code&gt; leverages &lt;code&gt;Find()&lt;/code&gt; to determine what components &lt;code&gt;x &amp;amp; y&lt;/code&gt; are in. If the roots are the same, &lt;code&gt;x &amp;amp; y&lt;/code&gt; are in the same component, and no action is taken. If the roots are different, this means &lt;code&gt;x &amp;amp; y&lt;/code&gt; are in separate components. These components are merged by pointing the root of one of the components to the root of the other (one root becomes the parent of the other).

&lt;ul&gt;
&lt;li&gt;How do we determine which component is the one to merge into the other? By using &lt;code&gt;rank&lt;/code&gt; or &lt;code&gt;size&lt;/code&gt; mentioned earlier.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Union by size&lt;/strong&gt; merges the smallest component (fewest elements) into the larger one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Union by rank&lt;/strong&gt; merges the component with the shorter tree into the taller one. Each componenet has a rank, which starts as 0. If two components are unioned and they have the same rank then the resulting component's rank is increased by 1. If the unioned components have a different rank, then the resulting component's rank is equal to the highest rank between the two. 

&lt;ul&gt;
&lt;li&gt;We use rank instead of tree height or depth because of a techninque called &lt;strong&gt;path compression&lt;/strong&gt; that changes the height/depth of the components over time&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Path compression is utilized in the &lt;code&gt;Find()&lt;/code&gt; operation to flatten a components tree. It does this by making every element of the component point to the components root (every element's parent is now the root of the component). This makes the &lt;code&gt;Find()&lt;/code&gt; operation &lt;em&gt;faster&lt;/em&gt; for that component, as it has a flatter chain to traverse when looking for a component's root.&lt;/li&gt;
&lt;li&gt;Union-find is often implemented with either an array or using a more &lt;a href="https://github.com/mission-peace/interview/blob/master/src/com/interview/graph/DisjointSet.java"&gt;object-oriented approach&lt;/a&gt;. In my implementations I use an array.&lt;/li&gt;
&lt;li&gt;Union-find is a useful data structure when used on graphs. Union-find can be used for things such as efficiently connecting vertices, finding connected components, &amp;amp; determining &lt;a href="https://en.wikipedia.org/wiki/Minimum_spanning_tree"&gt;minimum spanning tree&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using path compression, both union-find using &lt;code&gt;rank&lt;/code&gt; or &lt;code&gt;size&lt;/code&gt; have an amortized time complexity of &lt;code&gt;O(n)&lt;/code&gt; for &lt;code&gt;Union()&lt;/code&gt; &amp;amp; &lt;code&gt;Find()&lt;/code&gt; operations. Space is &lt;code&gt;O(n)&lt;/code&gt;. Without path compression, both &lt;code&gt;Union()&lt;/code&gt; &amp;amp; &lt;code&gt;Find()&lt;/code&gt; operations have a complexity of &lt;code&gt;O(log n)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below are array based union-find implementations by size &amp;amp; rank:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Extending An Iterator</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Sun, 29 Mar 2020 04:21:57 +0000</pubDate>
      <link>https://dev.to/jjb/part-22-extending-an-iterator-125c</link>
      <guid>https://dev.to/jjb/part-22-extending-an-iterator-125c</guid>
      <description>&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/discuss/interview-question/341818/Google-or-Onsite-or-Skip-Iterator"&gt;How to design a skip iterator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html"&gt;Java's Iterator reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerator-1"&gt;C#'s IEnumerator reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Iterator"&gt;Wikipedia article on iterators&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Iterators allow us to traverse and access elements in collections without the use of indexing.&lt;/li&gt;
&lt;li&gt;Iterators expose a consistent way to traverse all types of data structures, making the code more resilient to change.&lt;/li&gt;
&lt;li&gt;Iterators can allow the underlying collection to be modified during traversal, unlike when using indexing to iterate over a collection (like using a for loop on an array). This can mean insertion/deletion of items during traversal.&lt;/li&gt;
&lt;li&gt;Iterators exist in many languages, in C# they are called &lt;strong&gt;enumerators&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt;Time &amp;amp; Space complexity in the code comments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below you will find a class that takes an enumerator in it's constructor and extends the basic functionality of an iterator with the addition of &lt;code&gt;Skip()&lt;/code&gt;, &lt;code&gt;Peek()&lt;/code&gt;, &amp;amp; &lt;code&gt;Remove()&lt;/code&gt; operations:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Checking If An Undirected Graph Is Bipartite</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Thu, 19 Mar 2020 02:29:35 +0000</pubDate>
      <link>https://dev.to/jjb/part-21-checking-if-an-undirected-graph-is-bipartite-2n2d</link>
      <guid>https://dev.to/jjb/part-21-checking-if-an-undirected-graph-is-bipartite-2n2d</guid>
      <description>&lt;p&gt;&lt;em&gt;2021/01/05 - The previous C# code sample implemented the algorithm incorrectly. A corrected Java implementation has been added in its place.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with graphs, check out some of my earlier posts on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=za_BGCGJzSs"&gt;Video explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/GhjwOiJ4SqU?t=28"&gt;Brief video overview (clip in larger video)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Bipartite_graph#Testing_bipartiteness"&gt;Explanation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A bipartite graph (bigraph) is a graph where the vertices can be divided into two disjoint, independent, sets &lt;code&gt;u&lt;/code&gt; and &lt;code&gt;v&lt;/code&gt;. Every edge will connect a vertex from one set to the other (without self referencing edges - I.E edges going from a vertex in &lt;code&gt;u&lt;/code&gt; to another vertex in &lt;code&gt;u&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;One way to visualize a bipartite graph, is to colour all the vertices in a set the same colour. Set &lt;code&gt;u&lt;/code&gt; could be red vertices, whereas &lt;code&gt;v&lt;/code&gt; could be black. This would mean an edge would always consist of a red and black pair of vertices.&lt;/li&gt;
&lt;li&gt;This type of two-colouring is impossible in non-bipartite graphs. Think of a graph with three vertices arranged in a triangle. We cannot represent this graph as two independent sets, and we cannot two-colour it in such a way that will allow each edge to have different coloured endpoints.&lt;/li&gt;
&lt;li&gt;One way in which we can check if a graph is bipartite, is to run a depth-first search (DFS) over the vertices. Applying two colouring to the graph.

&lt;ul&gt;
&lt;li&gt;Start at a random vertex &lt;code&gt;v&lt;/code&gt; and colour it colour1 (red, for example).&lt;/li&gt;
&lt;li&gt;Colour all adjacent vertices &lt;code&gt;u&lt;/code&gt; the opposite colour of &lt;code&gt;v&lt;/code&gt;. For each adjacent &lt;code&gt;u&lt;/code&gt;, also recursively call our DFS routine.&lt;/li&gt;
&lt;li&gt;If a graph is bipartite, we can complete this two-colouring without a contradiction.&lt;/li&gt;
&lt;li&gt;If the graph is not bipartite, then at some point a vertex will get both colours - and this contradiction means we cannot achieve a two-colouring of the graph.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Time complexity is &lt;code&gt;O(v + e)&lt;/code&gt; for an adjacency list. Space complexity is &lt;code&gt;O(v)&lt;/code&gt;. For an adjacency matrix, the time &amp;amp; space complexity would be &lt;code&gt;O(v^2)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Undirected graph that can be two-coloured:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hkSb89PU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m5kgo8y9kkjcg8zcv1cq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hkSb89PU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m5kgo8y9kkjcg8zcv1cq.jpeg" alt="Bipartite"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Undirected graph that cannot be two-coloured:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q-VkfNsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b24uq3w61dabt8p7rejl.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q-VkfNsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b24uq3w61dabt8p7rejl.jpeg" alt="Not Bipartite"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below are implementations for checking if undirected graphs are bipartite. There is solutions for both undirected adjacency list &amp;amp; adjacency matrix representations of graphs:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>java</category>
    </item>
    <item>
      <title>Finding Strongly Connected Components in Directed Graphs using Tarjan's Algorithm</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Mon, 09 Mar 2020 03:51:58 +0000</pubDate>
      <link>https://dev.to/jjb/part-20-finding-strongly-connected-components-in-directed-graphs-using-tarjan-s-algorithm-48eb</link>
      <guid>https://dev.to/jjb/part-20-finding-strongly-connected-components-in-directed-graphs-using-tarjan-s-algorithm-48eb</guid>
      <description>&lt;p&gt;If you are unfamiliar with graphs, check out some of my earlier posts on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=TyWtx7q2D7Y"&gt;Video explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm"&gt;Article explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/williamfiset/Algorithms/blob/master/src/main/java/com/williamfiset/algorithms/graphtheory/TarjanSccSolverAdjacencyList.java"&gt;Implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tz-8X3gD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e8d54d3ffyhms5as94o8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tz-8X3gD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e8d54d3ffyhms5as94o8.jpg" alt="Strongly Connected Components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;strongly connected component&lt;/strong&gt; in a directed graph is a partition or sub-graph where each vertex of the component is reachable from every other vertex in the component. &lt;/li&gt;
&lt;li&gt;Strongly connected components are always the &lt;em&gt;maximal&lt;/em&gt; sub-graph, meaning none of their vertices are part of another strongly connected component.&lt;/li&gt;
&lt;li&gt;Finding strongly connected components is very similar to finding articulation points &amp;amp; bridges. Many of the solutions for finding them involve &lt;strong&gt;depth-first search&lt;/strong&gt; (DFS).&lt;/li&gt;
&lt;li&gt;One way to find strongly connected components is using &lt;strong&gt;Tarjan's Algorithm&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tarjan's Algorithm uses DFS and a stack to find strongly connected components.&lt;/li&gt;
&lt;li&gt;The algorithm overview is:

&lt;ul&gt;
&lt;li&gt;For every unvisited vertex &lt;code&gt;v&lt;/code&gt; in the graph, perform DFS.&lt;/li&gt;
&lt;li&gt;At the start of each DFS routine, mark the current vertex &lt;code&gt;v&lt;/code&gt; as visited, push &lt;code&gt;v&lt;/code&gt; onto the stack, and assign &lt;code&gt;v&lt;/code&gt; an ID and low-link value.&lt;/li&gt;
&lt;li&gt;Initially, like with articulation points &amp;amp; bridges, the ID and low-link values of &lt;code&gt;v&lt;/code&gt; will be the same. &lt;/li&gt;
&lt;li&gt;Increment the integer value we are using as the ID/low-link seed. So the next vertex &lt;code&gt;w&lt;/code&gt; to enter our DFS routine will get a higher value for both (compared to &lt;code&gt;v&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;For every adjacent vertex &lt;code&gt;u&lt;/code&gt; of &lt;code&gt;v&lt;/code&gt;, if &lt;code&gt;u&lt;/code&gt; is unvisited, perform DFS (recursive call).&lt;/li&gt;
&lt;li&gt;On exit of the recursive DFS call, or if &lt;code&gt;u&lt;/code&gt; had already been visited, check if &lt;code&gt;u&lt;/code&gt; is on the stack.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;u&lt;/code&gt; is on the stack, update the low-link value of &lt;code&gt;v&lt;/code&gt; to be smallest between &lt;code&gt;low-link[v]&lt;/code&gt; and &lt;code&gt;low-link[u]&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;low-link represents the &lt;em&gt;earliest&lt;/em&gt; ancestor of a vertex (a lower value means the vertex entered DFS earlier). In other words, low-link is the ID of the earliest vertex &lt;code&gt;y&lt;/code&gt; vertex &lt;code&gt;v&lt;/code&gt; is connected to.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;After exploring all adjacent vertices of &lt;code&gt;v&lt;/code&gt; check if the ID of &lt;code&gt;v&lt;/code&gt; is the same as it's low-link value&lt;/li&gt;
&lt;li&gt;If they are the same, then &lt;code&gt;v&lt;/code&gt; is the root of a strongly connected component.&lt;/li&gt;
&lt;li&gt;If they are the same, pop all vertices off the stack up to and including &lt;code&gt;v&lt;/code&gt;. All of these vertices represent a single strongly connected component&lt;/li&gt;
&lt;li&gt;Complete the above steps for the entire graph, and all strongly connected components will be discovered.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Time complexity of Tarjan's Algorithm is &lt;code&gt;O(v + e)&lt;/code&gt; - where &lt;code&gt;v&lt;/code&gt; is the number of vertices, and &lt;code&gt;e&lt;/code&gt; the number of edges, in a graph.&lt;/li&gt;
&lt;li&gt;Space is &lt;code&gt;O(v)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below are implementations for finding strongly connected components in undirected adjacency list &amp;amp; adjacency matrix representations of graphs:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Finding Articulation Points &amp; Bridges in Undirected Graphs</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Wed, 26 Feb 2020 05:03:32 +0000</pubDate>
      <link>https://dev.to/jjb/part-19-finding-articulation-points-bridges-in-undirected-graphs-26pc</link>
      <guid>https://dev.to/jjb/part-19-finding-articulation-points-bridges-in-undirected-graphs-26pc</guid>
      <description>&lt;p&gt;If you are unfamiliar with graphs, check out some of my earlier posts on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=aZXi1unBdJA"&gt;Video explanation of articulation points &amp;amp; bridges&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=2kREIkF9UAs"&gt;Video explanation and implementation for articulation points&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=iGsxKUzW3cs"&gt;Video on bridges &amp;amp; blocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mission-peace/interview/blob/master/src/com/interview/graph/ArticulationPoint.java"&gt;Articulation points implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/williamfiset/Algorithms/blob/master/src/main/java/com/williamfiset/algorithms/graphtheory/BridgesAdjacencyList.java"&gt;Bridges implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;component&lt;/strong&gt; is a sub-graph that is not connected to the rest of the graph.&lt;/li&gt;
&lt;li&gt;An articulation point is a vertex that when removed (along with it's edges) creates more components in the graph.&lt;/li&gt;
&lt;li&gt;Another name for articulation point is &lt;strong&gt;cut vertex&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A bridge is an edge that when removed creates more components in the graph.&lt;/li&gt;
&lt;li&gt;Another name for a bridge is &lt;strong&gt;cut-edge&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;We can use &lt;strong&gt;depth-first search&lt;/strong&gt; (DFS) to find all the articulation points or bridges in a graph.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There are two rules for finding articulation points in undirected graphs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The root vertex in a graph is an articulation point if it has more than one child.&lt;/li&gt;
&lt;li&gt;Any other vertex &lt;code&gt;v&lt;/code&gt; in the graph is an articulation point if it has a child &lt;code&gt;u&lt;/code&gt; that cannot reach any ancestors of &lt;code&gt;v&lt;/code&gt;,  without also visiting &lt;code&gt;v&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;This means that there is no &lt;strong&gt;back-edge&lt;/strong&gt; between &lt;code&gt;u&lt;/code&gt; and any ancestor before &lt;code&gt;v&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;How do we apply DFS and follow the above two rules?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We maintain a discovery time (or ID) for each vertex &lt;code&gt;v&lt;/code&gt; in the graph. We also keep track of the earliest vertex &lt;code&gt;y&lt;/code&gt; it is connected to - we call this the &lt;strong&gt;low-link&lt;/strong&gt; value (&lt;code&gt;y&lt;/code&gt; is the low-link vertex).&lt;/li&gt;
&lt;li&gt;So during DFS, for every vertex &lt;code&gt;v&lt;/code&gt; we visit we assign it an ID &amp;amp; a low-link value. To start, we set both ID/low-link to be the same integer that we will increment by 1 each time we visit a new vertex. (For example: root vertex will get 0 assigned to it for ID/low-link, then we will increment both by 1 for the next vertex).&lt;/li&gt;
&lt;li&gt;For every vertex &lt;code&gt;u&lt;/code&gt;, that is adjacent to &lt;code&gt;v&lt;/code&gt;, we will recursively call our DFS routine.&lt;/li&gt;
&lt;li&gt;When our DFS finds no more adjacent vertices to visit, the stack begins to unwind. As it unwinds, we will update our low-link value for each adjacent vertex (to represent the earliest ancestor it is connected to).&lt;/li&gt;
&lt;li&gt;If we find that the ID (visited time) of the current vertex &lt;code&gt;v&lt;/code&gt; is &lt;code&gt;&amp;lt;=&lt;/code&gt; the low-link value of our adjacent vertex &lt;code&gt;u&lt;/code&gt;, then &lt;code&gt;v&lt;/code&gt; is an articulation point.

&lt;ul&gt;
&lt;li&gt;This is because it means &lt;code&gt;u&lt;/code&gt; cannot reach one of it's ancestor vertices &lt;em&gt;without&lt;/em&gt; also visiting/going via &lt;code&gt;v&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Finding bridges is very similar to finding articulation points. The main changes to the algorithm are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We no longer need to keep track of how many children the root vertex has.&lt;/li&gt;
&lt;li&gt;Instead of checking if the ID of &lt;code&gt;v&lt;/code&gt; is &lt;code&gt;&amp;lt;=&lt;/code&gt; the low-link of &lt;code&gt;u&lt;/code&gt;, we just check if it's &lt;code&gt;&amp;lt;&lt;/code&gt;. 

&lt;ul&gt;
&lt;li&gt;We only check if it's less than, because if the values are the same then there is a back-edge present - and this means a bridge cannot exist&lt;/li&gt;
&lt;li&gt;A back-edge means that a neighbour &lt;code&gt;w&lt;/code&gt; of &lt;code&gt;u&lt;/code&gt; could have an edge connecting to &lt;code&gt;v&lt;/code&gt;. Creating a cycle. Meaning if &lt;code&gt;edge(u,v)&lt;/code&gt; is removed, then &lt;code&gt;u&lt;/code&gt; still connects to &lt;code&gt;v&lt;/code&gt; via &lt;code&gt;edge(w,v)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If there is no back-edge, or cycle, like described, then the ID of &lt;code&gt;v&lt;/code&gt; will always be less than the low-link of &lt;code&gt;u&lt;/code&gt; if a bridge is present. And this means if &lt;code&gt;edge(u,v)&lt;/code&gt; is removed, &lt;code&gt;u&lt;/code&gt; and all it's adjacent vertices will become disconnected from the graph - forming another component (and increasing the number of components in the graph).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time complexity is &lt;code&gt;O(v + e)&lt;/code&gt; for an adjacency list. Space complexity is &lt;code&gt;O(v)&lt;/code&gt;. For an adjacency matrix, the time &amp;amp; space complexity would be &lt;code&gt;O(v^2)&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Below is an example of an undirected graph with articulation points and bridges:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M8k6vY1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a2b6382pk7aeiuelnawo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M8k6vY1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a2b6382pk7aeiuelnawo.jpg" alt="Articulation points and bridgs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below are implementations for finding articulation points &amp;amp; bridges in undirected adjacency list &amp;amp; adjacency matrix representations of graphs:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Topological Sorting of Directed Acyclic Graphs (DAGs)</title>
      <dc:creator>JB</dc:creator>
      <pubDate>Fri, 21 Feb 2020 04:36:02 +0000</pubDate>
      <link>https://dev.to/jjb/part-18-topological-sorting-directed-acyclic-graphs-dags-37ca</link>
      <guid>https://dev.to/jjb/part-18-topological-sorting-directed-acyclic-graphs-dags-37ca</guid>
      <description>&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=AfSk24UTFS8&amp;amp;t=2511s"&gt;MIT video explaining topological sort&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=eL-KzMXSXXI"&gt;Video explanation and walkthrough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=ddTC4Zovtbc"&gt;Video explanation and implementation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Topological sort is an algorithm that produces a &lt;strong&gt;linear ordering&lt;/strong&gt; of a graph's vertices such that for every directed edge &lt;code&gt;v -&amp;gt; u&lt;/code&gt;, vertex &lt;code&gt;v&lt;/code&gt; comes before vertex &lt;code&gt;u&lt;/code&gt; in the ordering. &lt;/li&gt;
&lt;li&gt;There can be more than one valid topological ordering of a graph's vertices.&lt;/li&gt;
&lt;li&gt;Topological sort only works for &lt;strong&gt;Directed Acyclic Graphs&lt;/strong&gt; (&lt;strong&gt;DAGs&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Undirected graphs, or graphs with cycles (cyclic graphs), have edges where there is no clear start and end. Think of &lt;code&gt;v -&amp;gt; u&lt;/code&gt;, in an undirected graph this edge would be &lt;code&gt;v &amp;lt;--&amp;gt; u&lt;/code&gt;. The same is true for a graph with a back edge (cycle) - we do not know what the order should be as it is ambiguous as to which vertex comes before the other.&lt;/li&gt;
&lt;li&gt;Here is a visualization of what a topological sort might produce:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DAG before topological sort&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UqjMlNR5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1ckd1qm7h2ikbi3nkiiq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UqjMlNR5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1ckd1qm7h2ikbi3nkiiq.jpeg" alt="DAG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three valid topological orderings of the DAG's vertices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MbXkXOC7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v1w4m4k5rxadsc88v3t6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MbXkXOC7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v1w4m4k5rxadsc88v3t6.jpeg" alt="Topological ordering"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;One important thing to consider when thinking about topological ordering is the &lt;strong&gt;in-degree&lt;/strong&gt; and &lt;strong&gt;out-degree&lt;/strong&gt; of each vertex.

&lt;ul&gt;
&lt;li&gt;In-degree is how many edges point to a vertex (incoming edges).&lt;/li&gt;
&lt;li&gt;Out-degree is how many edges point from a vertex (outgoing edges).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Vertices with an in-degree of 0 will tend to be towards the beginning of a topological ordering, because no other vertex points to them.&lt;/li&gt;
&lt;li&gt;Vertices with an out-degree of 0 will be towards the end of a topological ordering, because they don't point to any vertices - they are solely destination vertices in directed edges.&lt;/li&gt;
&lt;li&gt;There are two main ways to perform topological sort: &lt;strong&gt;Kahn's Algorithm&lt;/strong&gt; &amp;amp; &lt;strong&gt;Depth-First Search&lt;/strong&gt; (DFS).&lt;/li&gt;
&lt;li&gt;Roberet Tarjan is credited with being the first to write about using DFS for topological sorting.&lt;/li&gt;
&lt;li&gt;Kahn's algorithm relies on pre-calculating the in-degree of each vertex.&lt;/li&gt;
&lt;li&gt;Tarjan's approach uses DFS to a achieve a topological ordering of a graph's vertices.&lt;/li&gt;
&lt;li&gt;In this post I will be covering DFS and &lt;em&gt;not&lt;/em&gt; Kahn's algorithm.&lt;/li&gt;
&lt;li&gt;If you wish to learn more about Kahn's algorithm &lt;a href="https://www.educative.io/edpresso/what-is-topological-sort"&gt;see this explanation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using DFS for topological sorting is actually &lt;em&gt;almost identical&lt;/em&gt; to vanilla DFS, the main difference is that we keep track of a collection of vertices to return (which will be the topological ordering of vertices).&lt;/li&gt;
&lt;li&gt;In Tarjan's approach we loop through each vertex of the graph

&lt;ul&gt;
&lt;li&gt;If we haven't visited the vertex before we run DFS on that vertex.&lt;/li&gt;
&lt;li&gt;We mark each vertex in the DFS routine as visited before exploring each of the vertex's neighbours. &lt;/li&gt;
&lt;li&gt;If a neighbour has already been visited, it is skipped. &lt;/li&gt;
&lt;li&gt;Before each DFS execution completes, it will add the current vertex to a &lt;code&gt;Stack&lt;/code&gt; or prepend it to a &lt;code&gt;List&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;List&lt;/code&gt; or &lt;code&gt;Stack&lt;/code&gt; represents the topological ordering of vertices. &lt;/li&gt;
&lt;li&gt;If we use a &lt;code&gt;Stack&lt;/code&gt; we can pop each vertex from the stack, and the order in which they are popped will be the topological order. &lt;/li&gt;
&lt;li&gt;For &lt;code&gt;List&lt;/code&gt;, if we always prepend (add new vertices at the start), then the list will represent our topological ordering at completion of the algorithm.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Stack&lt;/code&gt; has cost &lt;em&gt;after&lt;/em&gt; adding all vertices to it. &lt;code&gt;List&lt;/code&gt; has a cost each time we add to it (can't append, have to prepend).&lt;/li&gt;
&lt;li&gt;We could also append to a collection (like &lt;code&gt;List&lt;/code&gt;) and then reverse it after adding all vertices.&lt;/li&gt;
&lt;li&gt;Either way we choose will incur an &lt;code&gt;O(v)&lt;/code&gt; cost - so it is a matter of preference.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Run time of DFS for topological sort of an adjacency list is linear &lt;code&gt;O(v + e)&lt;/code&gt; - where &lt;code&gt;v&lt;/code&gt; is number of vertices and &lt;code&gt;e&lt;/code&gt; is number of edges. Space complexity is &lt;code&gt;O(v)&lt;/code&gt;. For an adjacency matrix, both are &lt;code&gt;O(v^2)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Some applications of topological sort:

&lt;ul&gt;
&lt;li&gt;Can be used to detect cycles and find strongly connected components in graphs. &lt;/li&gt;
&lt;li&gt;School: class prerequisites &amp;amp; what order you have to take the classes in.&lt;/li&gt;
&lt;li&gt;Build systems: What order should the dependencies get built in? Also helps to enforce that there are no circular dependencies (as topological sort detects cycles).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below are implementations of DFS for topological sorting of adjacency list &amp;amp; adjacency matrix representations of graphs:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As always, if you found any errors in this post please let me know!&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>algorithms</category>
      <category>datastructures</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
