Functional Programming
  • Preface
  • Getting Started
  • Sorting
    • Bubble Sort
    • Merge Sort
    • Insertion Sort
  • Stacks
    • Stack
  • Queues
    • Queue
    • Binary Heap (Priority Queue)
  • Trees
    • Binary Tree (Unbalanced)
    • Prefix Trie
  • Graphs
    • Undirected
    • Directed
    • Edge Weighted
  • Dynamic Programming
    • Knapsack
    • Longest Common Substring
    • Staircase
  • Leetcode/InterviewBit
    • 2 Sum [Easy]
    • Longest Valid Parentheses [Medium-Hard]
    • Kth Smallest Element [Medium]
    • Max Profit [2 variations: 1st Easy 2nd Hard]
    • Pretty Print 2D Matrix [Easy]
    • Max Contiguous Subarray (Kadane's) [Medium (just cause its tricky)]
    • Permutations [Medium]
    • Next Permutation [Medium]
Powered by GitBook
On this page

Was this helpful?

  1. Graphs

Edge Weighted

import scala.collection.mutable.{LinkedHashSet, SortedMap, PriorityQueue}
import scala.annotation.tailrec

sealed abstract class EdgeWeightedGraph[A](m: Map[A, Set[(A, Double)]]) {

    object weighteduf {

      type Id = Map[A, A]
      type Sz = Map[A, Int]

      val (id, sz) = m.keys.foldLeft(Map.empty[A, A] -> Map.empty[A, Int]) {
        case ((id, sz), k) => (id + (k -> k)) -> (sz + (k -> 1))
      }

      @tailrec
      def find(a: A, m: Id): A = {
        if (m(a) == a) a
        else find(m(a), m)
      }

      def connected(a: A, b: A, m: Id): Boolean =
        find(a, m) == find(b, m)

      def union(
          a: A,
          b: A,
          id: Id,
          sz: Sz
      ): (Id, Sz) = {

        val fa = find(a, id)
        val fb = find(b, id)
        if (fa == fb) {
          id -> sz
        } else {
          if (sz(fa) < sz(fb))
            id.updated(fa, fb) -> sz.updated(fb, sz(fb) + sz(fa))
          else id.updated(fb, fa) -> sz.updated(fa, sz(fa) + sz(fb))
        }

      }

    }

    def prims(start: A): Set[(A, A)] = {

      val keys = m.keySet

      implicit val ordering: Ordering[(A, A, Double)] =
        new Ordering[(A, A, Double)] {
          override def compare(x: (A, A, Double), y: (A, A, Double)): Int =
            implicitly[Ordering[Double]].compare(x._3, y._3) * -1
        }

      def go(
          queue: PriorityQueue[(A, A, Double)],
          added: Set[(A, A)],
          visited: Set[A],
          invalidated: Set[Set[A]]
      ): (Set[(A, A)], Set[A]) =
        if (visited.size == keys.size)
          added -> visited
        else {

          val queue1 = queue
            .dropWhile {
              case (v1, v2, _) => invalidated.contains(Set(v1, v2))
            }

          queue1.headOption
            .fold(
              added -> visited
            ) {
              case (v1, v2, _) =>
                val (nexts, inval) = m
                  .get(v2)
                  .fold(
                    (List.empty[(A, A, Double)], Set.empty[Set[A]])
                  ) { nextEdges =>
                    val (inval, next) = nextEdges.partition {
                      case (v, _) => visited.contains(v)
                    }
                    (next.map { case (v, distance) => (v2, v, distance) }.toList,
                     inval.map {
                       case (v, _) => Set(v2, v)
                     })
                  }

                queue1.dequeue()
                queue1.enqueue(nexts: _*)

                go(
                  queue1,
                  added + (v1 -> v2),
                  visited + v2,
                  invalidated ++ inval
                )
            }
        }

      val pq = new PriorityQueue[(A, A, Double)]()
      pq.enqueue(
        m.get(start)
          .fold(List.empty[(A, A, Double)])(_.map {
            case (v, distance) => (start, v, distance)
          }.toList): _*
      )

      go(pq, Set.empty, Set(start), Set.empty)._1
    }

    def kruskal(): Set[(A, A)] = {

      implicit val ord: Ordering[(Double, A, A)] =
        new Ordering[(Double, A, A)] {
          override def compare(x: (Double, A, A), y: (Double, A, A)): Int =
            implicitly[Ordering[Double]].compare(x._1, y._1) * -1
        }

      val (_, pq) =
        m.foldLeft(Set.empty[Set[A]] -> PriorityQueue.empty[(Double, A, A)]) {
          case ((added, pq), (edge1, edgeWeightSet)) =>
            edgeWeightSet.foldLeft(added -> pq) {
              case ((added, sm), (edge2, weight)) =>
                if (added.contains(Set(edge1, edge2))) added -> sm
                else
                  added + Set(edge1, edge2) ->
                    (pq += ((weight, edge1, edge2)))
            }
        }

      @tailrec
      def go(
          pq: PriorityQueue[(Double, A, A)],
          id: weighteduf.Id,
          sz: weighteduf.Sz,
          mst: Set[(A, A)]
      ): Set[(A, A)] =
        if (pq.isEmpty) mst
        else {
          val (_, e1, e2) = pq.dequeue()
          if (weighteduf.connected(e1, e2, id)) go(pq, id, sz, mst)
          else {
            val (id1, sz1) = weighteduf.union(e1, e2, id, sz)
            go(pq, id1, sz1, (mst + (e1 -> e2)))
          }
        }

      go(pq, weighteduf.id, weighteduf.sz, Set.empty[(A, A)])

    }

}
PreviousDirectedNextDynamic Programming

Last updated 6 years ago

Was this helpful?