diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100644
index 0000000..93d8007
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Run 'mvn clean install' and check if it succeeds
+echo "Running 'mvn clean install'..."
+if mvn clean install; then
+ echo "Build successful, proceeding with commit."
+else
+ echo "Build failed. Aborting commit."
+ exit 1
+fi
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index f548824..884aa8d 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,17 +4,15 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -27,14 +25,21 @@
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
@@ -137,12 +134,12 @@
-
-
+
+
-
+
@@ -150,12 +147,12 @@
-
-
+
+
-
+
@@ -163,12 +160,12 @@
-
-
-
+
+
+
-
+
@@ -176,13 +173,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
@@ -523,7 +535,71 @@
1729345170365
-
+
+
+ 1729348659507
+
+
+
+ 1729348659507
+
+
+
+ 1729416219895
+
+
+
+ 1729416219896
+
+
+
+ 1730103136030
+
+
+
+ 1730103136030
+
+
+
+ 1730103173375
+
+
+
+ 1730103173375
+
+
+
+ 1730103372472
+
+
+
+ 1730103372472
+
+
+
+ 1730274050189
+
+
+
+ 1730274050189
+
+
+
+ 1730537779798
+
+
+
+ 1730537779798
+
+
+
+ 1730571702127
+
+
+
+ 1730571702127
+
+
@@ -562,7 +638,8 @@
-
+
+
@@ -711,6 +788,11 @@
39
+
+ file://$PROJECT_DIR$/low-level-design/src/main/java/com/thealgorithm/splitwise/GroupBalanceSheet.java
+ 27
+
+
file://$PROJECT_DIR$/data-structures/src/main/java/com/thealgorithm/graph/CoursesII.java
44
@@ -731,11 +813,6 @@
-
-
-
-
-
diff --git a/data-structures/src/main/java/com/thealgorithm/graph/ConnectedComponentOnUndirectedGraph.java b/data-structures/src/main/java/com/thealgorithm/graph/ConnectedComponentOnUndirectedGraph.java
new file mode 100644
index 0000000..ee3a568
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/graph/ConnectedComponentOnUndirectedGraph.java
@@ -0,0 +1,66 @@
+package com.thealgorithm.graph;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author: Subham Santra
+ */
+public class ConnectedComponentOnUndirectedGraph {
+ public static void main(String[] args) {
+ // TEST 1
+ {
+ GraphCreator graphCreator =
+ GraphCreator.getUndirected(7)
+ .addEdge(1, 2, 1)
+ .addEdge(2, 3, 1)
+ .addEdge(3, 4, 1)
+ .addEdge(5, 6, 1);
+
+ System.out.println(
+ countOfConnectedComponents(graphCreator.getAdjacencyList(), graphCreator.getVertices()));
+ }
+
+ // TEST 2
+ {
+ GraphCreator graphCreator =
+ GraphCreator.getUndirected(7);
+ System.out.println(
+ countOfConnectedComponents(graphCreator.getAdjacencyList(), graphCreator.getVertices()));
+ }
+
+ // TEST 3
+ {
+ GraphCreator graphCreator =
+ GraphCreator.getUndirected(3)
+ .addEdge(1, 2)
+ .addEdge(2, 0)
+ .addEdge(1, 0);
+ System.out.println(
+ countOfConnectedComponents(graphCreator.getAdjacencyList(), graphCreator.getVertices()));
+ }
+ }
+
+ public static int countOfConnectedComponents(
+ Map> adjacencyList, Set> vertexSet) {
+ int count = 0;
+ Set visited = new HashSet<>();
+ for (Vertex vertex : vertexSet) {
+ if (!visited.contains(vertex.getKey())) {
+ count++;
+ DFS(adjacencyList, vertex.getKey(), visited);
+ }
+ }
+ return count;
+ }
+
+ private static void DFS(
+ Map> adjacencyList, int vertex, Set visited) {
+ if (visited.contains(vertex)) return;
+ visited.add(vertex);
+ for (int child : adjacencyList.get(vertex)) {
+ DFS(adjacencyList, child, visited);
+ }
+ }
+}
diff --git a/data-structures/src/main/java/com/thealgorithm/graph/DijkstraAlgorithm.java b/data-structures/src/main/java/com/thealgorithm/graph/DijkstraAlgorithm.java
new file mode 100644
index 0000000..9b7bcdd
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/graph/DijkstraAlgorithm.java
@@ -0,0 +1,78 @@
+package com.thealgorithm.graph;
+
+import static java.util.AbstractMap.*;
+
+import java.util.*;
+
+public class DijkstraAlgorithm {
+ public static class InvalidWeightException extends Exception {
+ private String msg;
+
+ public InvalidWeightException(String msg) {
+ super(msg);
+ this.msg = msg;
+ }
+ }
+
+ void dijkstra(int[][] graph, int n, int source) throws InvalidWeightException {
+ int[] dist = new int[n];
+ Arrays.fill(dist, Integer.MAX_VALUE);
+ dist[source] = 0;
+
+ Set shortestPathFound = new HashSet<>();
+ PriorityQueue> priorityQueue =
+ new PriorityQueue<>(Comparator.comparingInt(Entry::getValue));
+
+ priorityQueue.offer(new SimpleEntry<>(source, 0));
+ shortestPathFound.add(source);
+
+ while (!priorityQueue.isEmpty()) {
+ Entry shortedstEntry = priorityQueue.poll();
+ int node = shortedstEntry.getKey();
+ int cost = shortedstEntry.getValue();
+
+ for (int i = 0; i < n; ++i) {
+ if (graph[node][i] < 0) {
+ throw new InvalidWeightException("Invalid data");
+ }
+ if (node != i && graph[node][i] != 0) {
+ if (dist[i] > cost + graph[node][i]) {
+ dist[i] = cost + graph[node][i];
+ int finalI = i;
+ priorityQueue.removeIf(e -> e.getKey() == finalI);
+ priorityQueue.offer(new SimpleEntry<>(i, dist[i]));
+ }
+ }
+ }
+ shortestPathFound.add(node);
+ if (shortestPathFound.size() == n) break;
+ }
+
+ System.out.println(Arrays.toString(dist));
+ }
+
+ public static void main(String[] args) throws InvalidWeightException {
+
+ GraphCreator graphCreator =
+ GraphCreator.getUndirected(9)
+ .addEdge(0, 1, 4)
+ .addEdge(0, 7, 8)
+ .addEdge(1, 7, 11)
+ .addEdge(1, 2, 8)
+ .addEdge(2, 8, 2)
+ .addEdge(8, 6, 6)
+ .addEdge(8, 6, 6)
+ .addEdge(7, 6, 1)
+ .addEdge(7, 8, 7)
+ .addEdge(6, 5, 2)
+ .addEdge(2, 5, 4)
+ .addEdge(2, 3, 7)
+ .addEdge(5, 3, 14)
+ .addEdge(5, 4, 10)
+ .addEdge(3, 4, 9);
+
+ new DijkstraAlgorithm().dijkstra(graphCreator.getAdjacencyMatrix(), graphCreator.getSize(), 0);
+ new DijkstraAlgorithm().dijkstra(graphCreator.getAdjacencyMatrix(), graphCreator.getSize(), 8);
+ new DijkstraAlgorithm().dijkstra(graphCreator.getAdjacencyMatrix(), graphCreator.getSize(), 6);
+ }
+}
diff --git a/data-structures/src/main/java/com/thealgorithm/graph/GraphCreator.java b/data-structures/src/main/java/com/thealgorithm/graph/GraphCreator.java
new file mode 100644
index 0000000..240531a
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/graph/GraphCreator.java
@@ -0,0 +1,62 @@
+package com.thealgorithm.graph;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import lombok.Value;
+
+@Value
+public class GraphCreator {
+ int size;
+ int[][] adjacencyMatrix;
+ Map> adjacencyList;
+ Set> vertices;
+ Set> edgeSet;
+ boolean undirected;
+
+ private GraphCreator(int size, boolean undirected) {
+ this.size = size;
+ this.adjacencyMatrix = new int[size][size];
+ this.undirected = undirected;
+ this.adjacencyList = new HashMap<>();
+ this.vertices = new HashSet<>();
+ this.edgeSet = new HashSet<>();
+ for (int i = 0; i < size; ++i) {
+ vertices.add(Vertex.create(i));
+ }
+ for (int i = 0; i < size; ++i) {
+ adjacencyList.put(i, new HashSet<>());
+ }
+ }
+
+ public static GraphCreator getUndirected(int n) {
+ return new GraphCreator(n, true);
+ }
+
+ public static GraphCreator getDirected(int n) {
+ return new GraphCreator(n, false);
+ }
+
+ public GraphCreator addEdge(int u, int v) {
+ return addEdge(u, v, 1);
+ }
+
+ public GraphCreator addEdge(int u, int v, int w) {
+ addEdge0(u, v, w);
+ if (undirected) {
+ addEdge0(v, u, w);
+ }
+ return this;
+ }
+
+ private void addEdge0(int u, int v, int w) {
+ edgeSet.add(Edge.createEdge(u, v, w));
+ addToAdjacencyList(u, v);
+ adjacencyMatrix[u][v] = w;
+ }
+
+ private void addToAdjacencyList(int u, int v) {
+ adjacencyList.get(u).add(v);
+ }
+}
diff --git a/data-structures/src/main/java/com/thealgorithm/heap/TopKFrequentWords.java b/data-structures/src/main/java/com/thealgorithm/heap/TopKFrequentWords.java
new file mode 100644
index 0000000..b49042a
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/heap/TopKFrequentWords.java
@@ -0,0 +1,37 @@
+package com.thealgorithm.heap;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author: Subham Santra
+ */
+public class TopKFrequentWords {
+ public List topKFrequent(String[] words, int k) {
+ return Arrays.stream(words)
+ .collect(Collectors.toMap(Function.identity(), s -> 1, Integer::sum))
+ .entrySet()
+ .stream()
+ .sorted(
+ (kv1, kv2) -> {
+ int diff = kv1.getValue() - kv2.getValue();
+ if (diff == 0) {
+ return kv1.getKey().compareTo(kv2.getKey());
+ }
+ return -diff;
+ })
+ .limit(k)
+ .map(Map.Entry::getKey)
+ .collect(Collectors.toList());
+ }
+
+ public static void main(String[] args) throws IOException {
+ // System.out.println(
+ // new TopKFrequentWords()
+ // .topKFrequent(new String[] {"i", "love", "leetcode", "i", "love", "coding"}, 2));
+ }
+}
diff --git a/data-structures/src/main/java/com/thealgorithm/linkedlist/DoublyLinkedList.java b/data-structures/src/main/java/com/thealgorithm/linkedlist/DoublyLinkedList.java
new file mode 100644
index 0000000..4df8251
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/linkedlist/DoublyLinkedList.java
@@ -0,0 +1,21 @@
+package com.thealgorithm.linkedlist;
+
+/**
+ * @author: Subham Santra
+ */
+public class DoublyLinkedList {
+ DoublyLinkedListNode head;
+ DoublyLinkedListNode tail;
+
+ public void addLast(int data) {
+ if (isEmpty()) {
+ head = tail = new DoublyLinkedListNode(data, null, null);
+ } else {
+ tail.next = new DoublyLinkedListNode(data, null, null);
+ }
+ }
+
+ private boolean isEmpty() {
+ return head == null && tail == null;
+ }
+}
diff --git a/data-structures/src/main/java/com/thealgorithm/linkedlist/DoublyLinkedListNode.java b/data-structures/src/main/java/com/thealgorithm/linkedlist/DoublyLinkedListNode.java
new file mode 100644
index 0000000..5fe0ca2
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/linkedlist/DoublyLinkedListNode.java
@@ -0,0 +1,13 @@
+package com.thealgorithm.linkedlist;
+
+/**
+ * @author: Subham Santra
+ */
+public class DoublyLinkedListNode extends LinkedListNode {
+ DoublyLinkedListNode previous;
+
+ public DoublyLinkedListNode(int data, LinkedListNode next, DoublyLinkedListNode previous) {
+ super(data, next);
+ this.previous = previous;
+ }
+}
diff --git a/data-structures/src/main/java/com/thealgorithm/linkedlist/LinkedListNode.java b/data-structures/src/main/java/com/thealgorithm/linkedlist/LinkedListNode.java
new file mode 100644
index 0000000..c85f972
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/linkedlist/LinkedListNode.java
@@ -0,0 +1,12 @@
+package com.thealgorithm.linkedlist;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * @author: Subham Santra
+ */
+@AllArgsConstructor
+public class LinkedListNode {
+ int data;
+ LinkedListNode next;
+}
diff --git a/data-structures/src/main/java/com/thealgorithm/strings/LongestChunkedPalindromeDecomposition.java b/data-structures/src/main/java/com/thealgorithm/strings/LongestChunkedPalindromeDecomposition.java
new file mode 100644
index 0000000..5a122dc
--- /dev/null
+++ b/data-structures/src/main/java/com/thealgorithm/strings/LongestChunkedPalindromeDecomposition.java
@@ -0,0 +1,80 @@
+package com.thealgorithm.strings;
+
+/**
+ * @author: Subham Santra
+ */
+public class LongestChunkedPalindromeDecomposition {
+ static class Solution {
+ private final long p = 31;
+ private final long mod = (int) 1e9 + 7;
+ private final long[] p_pow = new long[1001];
+
+ public Solution() {
+ p_pow[0] = 1;
+ for (int i = 1; i <= 1000; ++i) {
+ p_pow[i] = p_pow[i - 1] * p;
+ p_pow[i] = (p_pow[i] + mod) % mod;
+ }
+ }
+
+ void rollingHash(long[] rh, String txt) {
+ for (int i = 0; i < txt.length(); ++i) {
+ int c = txt.charAt(i) - 'a' + 1;
+ rh[i + 1] = ((rh[i] * 31) % mod + c + mod) % mod;
+ }
+ }
+
+ long hash(long[] RH, int i, int j) {
+ return ((RH[j + 1] - RH[i] * p_pow[j - i + 1]) % mod + mod) % mod;
+ }
+
+ public int longestDecomposition(String text) {
+ int[][] DP = new int[text.length()][text.length()];
+ long[] RH = new long[text.length() + 1];
+ for (int i = 0; i < text.length(); ++i) {
+ for (int j = 0; j < text.length(); ++j) {
+ DP[i][j] = -1;
+ }
+ }
+ rollingHash(RH, text);
+ // System.out.println(Arrays.toString(RH));
+ return decompose(text, 0, text.length() - 1, DP, RH);
+ }
+
+ int decompose(String text, int lo, int hi, int[][] DP, long[] RH) {
+ if (lo == hi + 1) return 0;
+ if (lo > hi) return -1;
+
+ if (DP[lo][hi] != -1) return DP[lo][hi];
+
+ int ans = 1;
+
+ for (int len = 1; len <= (hi - lo + 1) / 2; ++len) {
+ long h1 = hash(RH, lo, lo + len - 1);
+ long h2 = hash(RH, hi - len + 1, hi);
+
+ // System.out.printf(
+ // "%s %d %s %d\n",
+ // text.substring(lo, lo + len), h1, text.substring(hi - len + 1, hi + 1), h2);
+
+ if (h1 == h2) {
+ int a = decompose(text, lo + len, hi - len, DP, RH);
+ if (a > -1) ans = Math.max(a + 2, ans);
+ }
+ }
+
+ return DP[lo][hi] = ans;
+ }
+ }
+
+ public static void main(String[] args) {
+ System.out.println(new Solution().longestDecomposition("ghiabcdefhelloadamhelloabcdefghi"));
+ System.out.println(
+ new Solution().longestDecomposition("wuamlwxskgjzegshjhcwchkgjzegshjwuamlwxs"));
+ System.out.println(new Solution().longestDecomposition("antaprezatepzapreanta"));
+ System.out.println(new Solution().longestDecomposition("aabaab"));
+ System.out.println(new Solution().longestDecomposition("aabaabaab"));
+ System.out.println(new Solution().longestDecomposition("aabaabaabaab"));
+ System.out.println(new Solution().longestDecomposition("aabaabaabaabc"));
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/CreateDirectory.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/CreateDirectory.java
new file mode 100644
index 0000000..329e5d5
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/CreateDirectory.java
@@ -0,0 +1,16 @@
+package com.thealgorithm.filesystem;
+
+/**
+ * @author: Subham Santra
+ */
+public class CreateDirectory extends FileCommand {
+ @Override
+ String command() {
+ return "mkdir";
+ }
+
+ @Override
+ FileNode execute(FileNode fileNode) throws NotSupportedException {
+ return fileNode.mkdir(command());
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/CreateFile.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/CreateFile.java
new file mode 100644
index 0000000..b9e031c
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/CreateFile.java
@@ -0,0 +1,16 @@
+package com.thealgorithm.filesystem;
+
+/**
+ * @author: Subham Santra
+ */
+public class CreateFile extends FileCommand {
+ @Override
+ String command() {
+ return "create_file";
+ }
+
+ @Override
+ FileNode execute(FileNode fileNode) {
+ return null;
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/Directory.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/Directory.java
new file mode 100644
index 0000000..5bc853f
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/Directory.java
@@ -0,0 +1,6 @@
+package com.thealgorithm.filesystem;
+
+/**
+ * @author: Subham Santra
+ */
+public class Directory {}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/FileCommand.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/FileCommand.java
new file mode 100644
index 0000000..76cfb06
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/FileCommand.java
@@ -0,0 +1,10 @@
+package com.thealgorithm.filesystem;
+
+/**
+ * @author: Subham Santra
+ */
+public abstract class FileCommand {
+ abstract String command();
+
+ abstract FileNode execute(FileNode fileNode) throws NotSupportedException;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/FileNode.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/FileNode.java
new file mode 100644
index 0000000..9f580e9
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/FileNode.java
@@ -0,0 +1,29 @@
+package com.thealgorithm.filesystem;
+
+import java.io.FileNotFoundException;
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ * @author: Subham Santra
+ */
+public interface FileNode {
+
+ String name();
+
+ FileNode mkdir(String name) throws NotSupportedException;
+
+ FileNode rm(String name) throws NotSupportedException;
+
+ FileNode cd(String nextNodeName) throws FileNotFoundException;
+
+ List pwd();
+
+ void ls() throws NotSupportedException;
+
+ boolean isDirectory();
+
+ Timestamp createTs();
+
+ FileNode parent();
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/FileSystem.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/FileSystem.java
new file mode 100644
index 0000000..19765f6
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/FileSystem.java
@@ -0,0 +1,9 @@
+package com.thealgorithm.filesystem;
+
+public abstract class FileSystem {
+ public abstract FileNode root();
+
+ public abstract FileNode currentNode();
+
+ public abstract void execute(FileCommand command);
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/MyUnix.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/MyUnix.java
new file mode 100644
index 0000000..129d818
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/MyUnix.java
@@ -0,0 +1,22 @@
+package com.thealgorithm.filesystem;
+
+/**
+ * @author: Subham Santra
+ */
+public class MyUnix extends FileSystem {
+
+ @Override
+ public FileNode root() {
+ return null;
+ }
+
+ @Override
+ public FileNode currentNode() {
+ return null;
+ }
+
+ @Override
+ public void execute(FileCommand command) {
+
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/NotSupportedException.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/NotSupportedException.java
new file mode 100644
index 0000000..290b46c
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/NotSupportedException.java
@@ -0,0 +1,10 @@
+package com.thealgorithm.filesystem;
+
+/**
+ * @author: Subham Santra
+ */
+public class NotSupportedException extends Throwable {
+ public NotSupportedException(String operationIsNotSupported) {
+ super(operationIsNotSupported);
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleAbstractFileNode.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleAbstractFileNode.java
new file mode 100644
index 0000000..7f776fd
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleAbstractFileNode.java
@@ -0,0 +1,78 @@
+package com.thealgorithm.filesystem;
+
+import java.io.FileNotFoundException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author: Subham Santra
+ */
+public abstract class SimpleAbstractFileNode implements FileNode {
+ private final String name;
+ private final Timestamp createTs;
+ private final List fileNodes;
+ private final FileNode parent;
+ private final boolean isDirectory;
+
+ public SimpleAbstractFileNode(
+ String name,
+ Timestamp createTs,
+ List fileNodes,
+ FileNode parent,
+ boolean isDirectory) {
+
+ this.name = name;
+ this.createTs = createTs;
+ this.fileNodes = fileNodes;
+ this.parent = parent;
+ this.isDirectory = isDirectory;
+ }
+
+ @Override
+ public FileNode parent() {
+ return parent;
+ }
+
+ @Override
+ public String name() {
+ return this.name;
+ }
+
+ @Override
+ public FileNode cd(String nextNodeName) throws FileNotFoundException {
+ if (nextNodeName.equals("..")) {
+ return parent();
+ }
+
+ return fileNodes.stream()
+ .filter(fn -> fn.isDirectory() && fn.name().equals(nextNodeName))
+ .findFirst()
+ .orElseThrow(() -> new FileNotFoundException(nextNodeName));
+ }
+
+ @Override
+ public List pwd() {
+ List workingDir = new ArrayList<>();
+ FileNode fn = this;
+ while (fn != null) {
+ workingDir.addLast(fn);
+ fn = fn.parent();
+ }
+ return workingDir;
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return isDirectory;
+ }
+
+ @Override
+ public Timestamp createTs() {
+ return createTs;
+ }
+
+ protected List fileNodes() {
+ return fileNodes;
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleDirectory.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleDirectory.java
new file mode 100644
index 0000000..9dd119c
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleDirectory.java
@@ -0,0 +1,41 @@
+package com.thealgorithm.filesystem;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author: Subham Santra
+ */
+public class SimpleDirectory extends SimpleAbstractFileNode {
+ public SimpleDirectory(
+ String name,
+ Timestamp createTs,
+ List fileNodes,
+ FileNode parent,
+ boolean isDirectory) {
+ super(name, createTs, fileNodes, parent, isDirectory);
+ }
+
+ @Override
+ public FileNode mkdir(String name) {
+ SimpleDirectory simpleDirectory =
+ new SimpleDirectory(
+ name, new Timestamp(System.currentTimeMillis()), new ArrayList<>(), this, true);
+ this.fileNodes().add(simpleDirectory);
+ return simpleDirectory;
+ }
+
+ @Override
+ public FileNode rm(String name) {
+ this.fileNodes().removeIf(fn -> fn.name().equalsIgnoreCase(name));
+ return this;
+ }
+
+ @Override
+ public void ls() {
+ for (FileNode fileNode : this.fileNodes()) {
+ System.out.printf("%s %s %s\n", name(), createTs(), isDirectory() ? "dir" : "file");
+ }
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleFile.java b/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleFile.java
new file mode 100644
index 0000000..d847181
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/filesystem/SimpleFile.java
@@ -0,0 +1,33 @@
+package com.thealgorithm.filesystem;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+/**
+ * @author: Subham Santra
+ */
+public class SimpleFile extends SimpleAbstractFileNode {
+ public SimpleFile(
+ String name,
+ Timestamp createTs,
+ List fileNodes,
+ FileNode parent,
+ boolean isDirectory) {
+ super(name, createTs, fileNodes, parent, isDirectory);
+ }
+
+ @Override
+ public FileNode mkdir(String name) throws NotSupportedException {
+ throw new NotSupportedException("operation is not supported");
+ }
+
+ @Override
+ public FileNode rm(String name) throws NotSupportedException {
+ throw new NotSupportedException("operation is not supported");
+ }
+
+ @Override
+ public void ls() throws NotSupportedException {
+ throw new NotSupportedException("operation is not supported");
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/FourWheeler.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/FourWheeler.java
new file mode 100644
index 0000000..ac97a2f
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/FourWheeler.java
@@ -0,0 +1,29 @@
+package com.thealgorithm.parkinglot;
+
+import lombok.AllArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author: Subham Santra
+ */
+@Setter
+@AllArgsConstructor
+public class FourWheeler extends Vehicle {
+ private boolean isEntered;
+ private String vehicleNumber;
+
+ @Override
+ String vehicleNumber() {
+ return vehicleNumber;
+ }
+
+ @Override
+ public boolean entered() {
+ return isEntered;
+ }
+
+ @Override
+ public void markEntered() {
+ this.isEntered = true;
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/Gate.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/Gate.java
new file mode 100644
index 0000000..bfbf00c
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/Gate.java
@@ -0,0 +1,20 @@
+package com.thealgorithm.parkinglot;
+
+import com.thealgorithm.parkinglot.model.Attendant;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.concurrent.BlockingDeque;
+
+/**
+ * @author: Subham Santra
+ */
+@Setter
+@AllArgsConstructor
+@Getter
+public abstract class Gate {
+ private int gateNo;
+ private Attendant attendant;
+ private BlockingDeque vehicles;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingFloor.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingFloor.java
new file mode 100644
index 0000000..ba35397
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingFloor.java
@@ -0,0 +1,42 @@
+package com.thealgorithm.parkinglot;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author: Subham Santra
+ */
+@Getter
+@AllArgsConstructor
+public class ParkingFloor {
+ private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+ private Lock readLock = readWriteLock.readLock();
+ private Lock writeLock = readWriteLock.writeLock();
+
+ private List parkingSpots;
+
+ public void tryPark(Vehicle vehicle) {}
+
+ public CompletableFuture getAvailable() {
+ return CompletableFuture.supplyAsync(
+ () -> {
+ readLock.lock();
+ ParkingSpot availableParkingSpot = null;
+
+ for (ParkingSpot parkingSpot : parkingSpots) {
+ if (parkingSpot.isAvailable()) {
+ availableParkingSpot = parkingSpot;
+ break;
+ }
+ }
+
+ readLock.unlock();
+ return availableParkingSpot;
+ });
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingLotSystem.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingLotSystem.java
new file mode 100644
index 0000000..18dbe29
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingLotSystem.java
@@ -0,0 +1,60 @@
+package com.thealgorithm.parkinglot;
+
+import com.thealgorithm.parkinglot.model.Attendant;
+import com.thealgorithm.parkinglot.model.EntryGate;
+import com.thealgorithm.parkinglot.model.ExitGate;
+import java.util.List;
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * @author: Subham Santra
+ */
+public class ParkingLotSystem {
+ private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+ private Lock readLock = readWriteLock.readLock();
+ private Lock writeLock = readWriteLock.writeLock();
+ private final List exitGates;
+ private final List entryGates;
+ private final List parkingFloors;
+ private final BlockingDeque availableAttendants;
+
+ public ParkingLotSystem(
+ List exitGates, List entryGates, List parkingFloors) {
+ this.exitGates = exitGates;
+ this.entryGates = entryGates;
+ this.parkingFloors = parkingFloors;
+ this.availableAttendants = new LinkedBlockingDeque<>();
+ }
+
+ public void addAttendant(Attendant attendant) {
+ availableAttendants.addLast(attendant);
+ }
+
+ public CompletableFuture tryEntry(EntryGate entryGate, Vehicle vehicle) {
+ return entryGate.tryEntry(vehicle);
+ }
+
+ public CompletableFuture tryExit(ExitGate exitGate, Vehicle vehicle) {
+ return exitGate.tryExit(vehicle);
+ }
+
+ public CompletableFuture tryPark(Vehicle vehicle) {
+ return CompletableFuture.runAsync(
+ () -> {
+ if (vehicle == null) throw new NullPointerException();
+ if (!vehicle.entered()) throw new RuntimeException();
+
+ readLock.lock();
+ for (ParkingFloor parkingFloor : this.parkingFloors) {
+ CompletableFuture available = parkingFloor.getAvailable();
+ available.thenAccept(parkingSpot -> parkingSpot.park(vehicle)).join();
+ }
+ readLock.unlock();
+ });
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingResponse.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingResponse.java
new file mode 100644
index 0000000..898409b
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingResponse.java
@@ -0,0 +1,18 @@
+package com.thealgorithm.parkinglot;
+
+import java.sql.Timestamp;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author: Subham Santra
+ */
+@AllArgsConstructor
+@Getter
+@Setter
+public class ParkingResponse {
+ private Vehicle vehicle;
+ private int floorNumber;
+ private Timestamp entryTs;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingSpot.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingSpot.java
new file mode 100644
index 0000000..8d3bc41
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/ParkingSpot.java
@@ -0,0 +1,22 @@
+package com.thealgorithm.parkinglot;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author: Subham Santra
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class ParkingSpot {
+ private int spotNumber;
+ private boolean isAvailable;
+ private Vehicle vehicle;
+
+ public void park(Vehicle vehicle) {
+ this.vehicle = vehicle;
+ this.isAvailable = false;
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentRequest.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentRequest.java
new file mode 100644
index 0000000..80730d9
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentRequest.java
@@ -0,0 +1,12 @@
+package com.thealgorithm.parkinglot;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * @author: Subham Santra
+ */
+@AllArgsConstructor
+public class PaymentRequest {
+ String paymentId;
+ Double amount;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentResponse.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentResponse.java
new file mode 100644
index 0000000..d79327d
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentResponse.java
@@ -0,0 +1,13 @@
+package com.thealgorithm.parkinglot;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * @author: Subham Santra
+ */
+@AllArgsConstructor
+public class PaymentResponse {
+ String paymentId;
+ Double amount;
+ PaymentStatus paymentStatus;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentService.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentService.java
new file mode 100644
index 0000000..3858bc9
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentService.java
@@ -0,0 +1,29 @@
+package com.thealgorithm.parkinglot;
+
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @author: Subham Santra
+ */
+public class PaymentService {
+ private final Random random = new Random();
+
+ public CompletableFuture doPayment(PaymentRequest paymentRequest) {
+ return CompletableFuture.supplyAsync(
+ () -> {
+ try {
+ Thread.sleep(random.nextInt(10) * 1000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ if (Math.random() > 0.85) {
+ return new PaymentResponse(
+ paymentRequest.paymentId, paymentRequest.amount, PaymentStatus.FAIL);
+ } else {
+ return new PaymentResponse(
+ paymentRequest.paymentId, paymentRequest.amount, PaymentStatus.SUCCESS);
+ }
+ });
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentStatus.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentStatus.java
new file mode 100644
index 0000000..fe4e8c3
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/PaymentStatus.java
@@ -0,0 +1,5 @@
+package com.thealgorithm.parkinglot;
+
+public enum PaymentStatus {
+ SUCCESS, FAIL
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/Test.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/Test.java
new file mode 100644
index 0000000..8d27859
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/Test.java
@@ -0,0 +1,30 @@
+package com.thealgorithm.parkinglot;
+
+import com.thealgorithm.parkinglot.model.EntryGate;
+import com.thealgorithm.parkinglot.model.ExitGate;
+
+import java.util.List;
+import java.util.concurrent.LinkedBlockingDeque;
+
+/**
+ * @author: Subham Santra
+ */
+public class Test {
+ public static void main(String[] args) {
+ List exitGates =
+ List.of(
+ new ExitGate(100, null, new LinkedBlockingDeque<>(2)),
+ new ExitGate(101, null, new LinkedBlockingDeque<>(4)),
+ new ExitGate(102, null, new LinkedBlockingDeque<>(5)));
+
+ List entryGates =
+ List.of(
+ new EntryGate(300, null, new LinkedBlockingDeque<>(4)),
+ new EntryGate(301, null, new LinkedBlockingDeque<>(4)),
+ new EntryGate(302, null, new LinkedBlockingDeque<>(4)));
+
+
+
+// ParkingLotSystem parkingLotSystem = new ParkingLotSystem();
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/TwoWheeler.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/TwoWheeler.java
new file mode 100644
index 0000000..d444b37
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/TwoWheeler.java
@@ -0,0 +1,24 @@
+package com.thealgorithm.parkinglot;
+
+/**
+ * @author: Subham Santra
+ */
+public class TwoWheeler extends Vehicle {
+ private String vehicleNumber;
+ private boolean isEntered;
+
+ @Override
+ public void markEntered() {
+ this.isEntered = true;
+ }
+
+ @Override
+ String vehicleNumber() {
+ return vehicleNumber;
+ }
+
+ @Override
+ public boolean entered() {
+ return isEntered;
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/Vehicle.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/Vehicle.java
new file mode 100644
index 0000000..d19da29
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/Vehicle.java
@@ -0,0 +1,15 @@
+package com.thealgorithm.parkinglot;
+
+import lombok.Getter;
+
+/**
+ * @author: Subham Santra
+ */
+@Getter
+public abstract class Vehicle {
+ public abstract void markEntered();
+
+ abstract String vehicleNumber();
+
+ public abstract boolean entered();
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/Attendant.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/Attendant.java
new file mode 100644
index 0000000..3912c25
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/Attendant.java
@@ -0,0 +1,54 @@
+package com.thealgorithm.parkinglot.model;
+
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+
+import com.thealgorithm.parkinglot.PaymentRequest;
+import com.thealgorithm.parkinglot.PaymentService;
+import com.thealgorithm.parkinglot.Vehicle;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author: Subham Santra
+ */
+@AllArgsConstructor
+@Getter
+@Setter
+public class Attendant {
+ private String name;
+ private EntryGate entryGate;
+ private ExitGate exitGate;
+ private PaymentService paymentService;
+
+ public CompletableFuture askEntry(Vehicle vehicle) {
+ return CompletableFuture.supplyAsync(
+ () -> {
+ while (true) {
+ if (entryGate.getVehicles().peekFirst() != vehicle) {
+ continue;
+ }
+ Vehicle polledFirst = entryGate.getVehicles().pollFirst();
+ polledFirst.markEntered();
+ }
+ });
+ }
+
+ public CompletableFuture askExit(Vehicle vehicle) {
+ return CompletableFuture.supplyAsync(
+ () -> {
+ while (true) {
+ if (entryGate.getVehicles().peekFirst() != vehicle) {
+ continue;
+ }
+ Vehicle polledFirst = entryGate.getVehicles().pollFirst();
+ if (polledFirst.entered()) {
+ paymentService.doPayment(new PaymentRequest(UUID.randomUUID().toString(), 10D));
+ } else {
+ throw new RuntimeException("Unknown Vehicle");
+ }
+ }
+ });
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/EntryGate.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/EntryGate.java
new file mode 100644
index 0000000..a62a723
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/EntryGate.java
@@ -0,0 +1,21 @@
+package com.thealgorithm.parkinglot.model;
+
+import com.thealgorithm.parkinglot.Gate;
+import com.thealgorithm.parkinglot.Vehicle;
+
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @author: Subham Santra
+ */
+public class EntryGate extends Gate {
+ public EntryGate(int gateNo, Attendant attendant, BlockingDeque vehicles) {
+ super(gateNo, attendant, vehicles);
+ }
+
+ public CompletableFuture tryEntry(Vehicle vehicle) {
+ this.getVehicles().addLast(vehicle);
+ return this.getAttendant().askEntry(vehicle);
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/ExitGate.java b/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/ExitGate.java
new file mode 100644
index 0000000..2d4721c
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/model/ExitGate.java
@@ -0,0 +1,21 @@
+package com.thealgorithm.parkinglot.model;
+
+import com.thealgorithm.parkinglot.Gate;
+import com.thealgorithm.parkinglot.Vehicle;
+
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @author: Subham Santra
+ */
+public class ExitGate extends Gate {
+ public ExitGate(int gateNo, Attendant attendant, BlockingDeque vehicles) {
+ super(gateNo, attendant, vehicles);
+ }
+
+ public CompletableFuture tryExit(Vehicle vehicle) {
+ this.getVehicles().addLast(vehicle);
+ return this.getAttendant().askExit(vehicle);
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/parkinglot/requirement.md b/low-level-design/src/main/java/com/thealgorithm/parkinglot/requirement.md
new file mode 100644
index 0000000..5c85d24
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/parkinglot/requirement.md
@@ -0,0 +1,23 @@
+## Requirements of the parking lot
+1. There should be multiple levels
+2. There should be multiple entry gates
+3. There should be multiple exits
+4. There should be attendants at each gate
+5. In the exist gates it will ask for hourly charges
+6. Display of availble spots at each floor
+
+### Actors
+1. **ParkingLotSystem**
+ 1. Add new attendants
+ 2. Remove attendants
+ 3. Assign attendants to exits
+2. **ParkingFloor**
+ 1. View dashboard
+ 2. Add new spot
+ 3. Remove an old spot
+ 4. Park a car in a spot and generate a coupon code
+3. **At exit gates**
+ 1. The cars will be asked to show the coupon
+ 2. Will be charged the cost
+4. **At entry gates**
+ 1. The cars will get entry only one at a time in one entry gate.
\ No newline at end of file
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/BalanceSheet.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/BalanceSheet.java
new file mode 100644
index 0000000..3a92119
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/BalanceSheet.java
@@ -0,0 +1,9 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public abstract class BalanceSheet {
+
+ abstract void update(User paidBy, User borrower, Double amount);
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/BalanceSheetEntry.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/BalanceSheetEntry.java
new file mode 100644
index 0000000..72d67a2
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/BalanceSheetEntry.java
@@ -0,0 +1,15 @@
+package com.thealgorithm.splitwise;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * @author: Subham Santra
+ */
+@Data
+@AllArgsConstructor
+public class BalanceSheetEntry {
+ User owner;
+ User other;
+ Double amount;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/DebtResolverType.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/DebtResolverType.java
new file mode 100644
index 0000000..be6ae16
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/DebtResolverType.java
@@ -0,0 +1,9 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public enum DebtResolverType {
+ SIMPLE,
+ SMART
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/Expense.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/Expense.java
new file mode 100644
index 0000000..8c45993
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/Expense.java
@@ -0,0 +1,17 @@
+package com.thealgorithm.splitwise;
+
+import lombok.Builder;
+import lombok.Value;
+
+import java.util.List;
+
+/**
+ * @author: Subham Santra
+ */
+@Value
+@Builder
+public class Expense {
+ Double totalAmount;
+ User paidBy;
+ List userSplits;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/Group.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/Group.java
new file mode 100644
index 0000000..f37dc48
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/Group.java
@@ -0,0 +1,61 @@
+package com.thealgorithm.splitwise;
+
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Data;
+import lombok.ToString;
+
+/**
+ * @author: Subham Santra
+ */
+@Data
+@ToString(onlyExplicitlyIncluded = true)
+public class Group {
+ @ToString.Include String name;
+ @ToString.Include List users;
+ ResolverStrategy resolverStrategy;
+ GroupBalanceSheet groupBalanceSheet;
+ GroupExpenseValidator groupExpenseValidator;
+
+ public Group(String name) {
+ this.name = name;
+ users = new ArrayList<>();
+ resolverStrategy = null;
+ groupBalanceSheet = new GroupBalanceSheet();
+ groupExpenseValidator = new GroupExpenseValidator(this);
+ groupBalanceSheet.setGroup(this);
+ }
+
+ void changeDebtResolver(DebtResolverType debtResolverType) {
+ this.resolverStrategy = ResolverStrategyFactory.resolverStrategy(debtResolverType);
+ }
+
+ void add(User user) {
+ this.users.add(user);
+ this.getGroupBalanceSheet().add(user);
+ }
+
+ void add(Expense expense) throws UserIsNotPartOfGroupException, InvalidSplitException {
+ groupExpenseValidator.validate(expense);
+
+ Double totalAmount = expense.getTotalAmount();
+ for (UserSplit eachUserSplit : expense.getUserSplits()) {
+ User user = eachUserSplit.getUser();
+ Double shareAmount = eachUserSplit.getShareAmount();
+ if (user.equals(expense.getPaidBy())) {
+ double totalGetBack =
+ user.getPersonalBalanceSheet().getTotalGetBack() + (totalAmount - shareAmount);
+ user.getPersonalBalanceSheet().setTotalGetBack(totalGetBack);
+ } else {
+ PersonalBalanceSheet personalBalanceSheet = user.getPersonalBalanceSheet();
+ Double totalOweAmount = personalBalanceSheet.getTotalOwe() + eachUserSplit.getShareAmount();
+ personalBalanceSheet.setTotalOwe(totalOweAmount);
+ groupBalanceSheet.update(expense.getPaidBy(), user, eachUserSplit.getShareAmount());
+ }
+ }
+ }
+
+ void resolve() throws OperationNotSupportedException {
+ resolverStrategy.resolveBalanceSheet(getGroupBalanceSheet());
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/GroupBalanceSheet.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/GroupBalanceSheet.java
new file mode 100644
index 0000000..47acee2
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/GroupBalanceSheet.java
@@ -0,0 +1,47 @@
+package com.thealgorithm.splitwise;
+
+import java.util.HashMap;
+import java.util.Map;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author: Subham Santra
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GroupBalanceSheet extends BalanceSheet {
+ private Group group;
+ private Map> balanceSheetEntryMap = new HashMap<>();
+
+ public void add(User user) {
+ balanceSheetEntryMap.put(user, new HashMap<>());
+ }
+
+ @Override
+ void update(User paidBy, User borrower, Double amount) {
+ update0(paidBy, borrower, amount);
+ update0(borrower, paidBy, -amount);
+ }
+
+ private void update0(User paidBy, User borrower, Double amount) {
+ Map paidUserBalanceSheet = balanceSheetEntryMap.get(paidBy);
+ paidUserBalanceSheet.putIfAbsent(borrower, new BalanceSheetEntry(paidBy, borrower, 0D));
+ paidUserBalanceSheet
+ .get(borrower)
+ .setAmount(paidUserBalanceSheet.get(borrower).getAmount() + amount);
+ }
+
+ public void print() {
+ System.out.println("SHOWING BALANCESHEET FOR " + group.name);
+ balanceSheetEntryMap.forEach(
+ (user, map) -> {
+ System.out.printf("BALANCE FOR %s\n", user);
+
+ map.forEach(
+ (u, e) -> {
+ System.out.printf("%s %s\n", u, e.getAmount());
+ });
+ });
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/GroupExpenseValidator.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/GroupExpenseValidator.java
new file mode 100644
index 0000000..e4468c4
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/GroupExpenseValidator.java
@@ -0,0 +1,17 @@
+package com.thealgorithm.splitwise;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author: Subham Santra
+ */
+@AllArgsConstructor
+@Getter
+@Setter
+public class GroupExpenseValidator {
+ private Group group;
+
+ void validate(Expense expense) throws UserIsNotPartOfGroupException, InvalidSplitException {}
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/InvalidSplitException.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/InvalidSplitException.java
new file mode 100644
index 0000000..0a64124
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/InvalidSplitException.java
@@ -0,0 +1,6 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public class InvalidSplitException extends Exception {}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/Main.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/Main.java
new file mode 100644
index 0000000..7dc7984
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/Main.java
@@ -0,0 +1,61 @@
+package com.thealgorithm.splitwise;
+
+import java.util.List;
+
+/**
+ * @author: Subham Santra
+ */
+public class Main {
+ public static void main(String[] args)
+ throws InvalidSplitException, UserIsNotPartOfGroupException {
+ User subham = new User("subham");
+ User shyam = new User("Shyam");
+ User ram = new User("Ram");
+ User babubhaiya = new User("Babubhaiya");
+ User biltu = new User("Biltu");
+ User hari = new User("Hari");
+ User mangal = new User("Mangal");
+ User charan = new User("Charan");
+
+ Group picnicWala = new Group("PicnicWala");
+ Group officeWala = new Group("OfficeWala");
+ Group flatWala = new Group("FlatWala");
+
+ picnicWala.add(subham);
+ picnicWala.add(shyam);
+ picnicWala.add(ram);
+
+ officeWala.add(babubhaiya);
+ officeWala.add(biltu);
+ officeWala.add(hari);
+
+ flatWala.add(mangal);
+ flatWala.add(hari);
+ flatWala.add(charan);
+ flatWala.add(subham);
+
+ picnicWala.add(
+ Expense.builder()
+ .paidBy(subham)
+ .totalAmount(60D)
+ .userSplits(
+ List.of(
+ UserSplit.builder().user(subham).shareAmount(20D).build(),
+ UserSplit.builder().user(shyam).shareAmount(20D).build(),
+ UserSplit.builder().user(ram).shareAmount(20D).build()))
+ .build());
+
+ picnicWala.add(
+ Expense.builder()
+ .paidBy(shyam)
+ .totalAmount(60D)
+ .userSplits(
+ List.of(
+ UserSplit.builder().user(subham).shareAmount(20D).build(),
+ UserSplit.builder().user(shyam).shareAmount(20D).build(),
+ UserSplit.builder().user(ram).shareAmount(20D).build()))
+ .build());
+
+ picnicWala.getGroupBalanceSheet().print();
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/OperationNotSupportedException.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/OperationNotSupportedException.java
new file mode 100644
index 0000000..642ecb5
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/OperationNotSupportedException.java
@@ -0,0 +1,10 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public class OperationNotSupportedException extends Throwable {
+ public OperationNotSupportedException(String message) {
+ super(message);
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/PersonalBalanceSheet.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/PersonalBalanceSheet.java
new file mode 100644
index 0000000..da99707
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/PersonalBalanceSheet.java
@@ -0,0 +1,20 @@
+package com.thealgorithm.splitwise;
+
+import java.util.HashMap;
+import java.util.Map;
+import lombok.Data;
+
+/**
+ * @author: Subham Santra
+ */
+@Data
+public class PersonalBalanceSheet extends BalanceSheet {
+ Double totalOwe = 0D;
+ Double totalGetBack = 0D;
+ Map balanceSheetEntryMap = new HashMap<>(); // otherUser --> entry
+
+ @Override
+ void update(User paidBy, User borrower, Double amount) {
+
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/ResolverStrategy.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/ResolverStrategy.java
new file mode 100644
index 0000000..921e7ff
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/ResolverStrategy.java
@@ -0,0 +1,9 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+@FunctionalInterface
+public interface ResolverStrategy {
+ void resolveBalanceSheet(BalanceSheet balanceSheet) throws OperationNotSupportedException;
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/ResolverStrategyFactory.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/ResolverStrategyFactory.java
new file mode 100644
index 0000000..2d159bf
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/ResolverStrategyFactory.java
@@ -0,0 +1,25 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public class ResolverStrategyFactory {
+ public static ResolverStrategy resolverStrategy(DebtResolverType resolverStyle) {
+ switch (resolverStyle) {
+ case SMART -> {
+ return new SmartDebtResolverStrategy();
+ }
+ case SIMPLE -> {
+ return new SimpleDebtResolverStrategy();
+ }
+ default -> {
+ return new ResolverStrategy() {
+ @Override
+ public void resolveBalanceSheet(BalanceSheet balanceSheet) {
+ // DO NOTHING
+ }
+ };
+ }
+ }
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/SimpleDebtResolverStrategy.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/SimpleDebtResolverStrategy.java
new file mode 100644
index 0000000..c933cd4
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/SimpleDebtResolverStrategy.java
@@ -0,0 +1,17 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public class SimpleDebtResolverStrategy implements ResolverStrategy {
+ @Override
+ public void resolveBalanceSheet(BalanceSheet balanceSheet) throws OperationNotSupportedException {
+ // Do something
+ if (!(balanceSheet instanceof GroupBalanceSheet)) {
+ throw new OperationNotSupportedException(
+ "The given balance sheet is not a Group balance sheet");
+ }
+
+
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/SmartDebtResolverStrategy.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/SmartDebtResolverStrategy.java
new file mode 100644
index 0000000..629abbb
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/SmartDebtResolverStrategy.java
@@ -0,0 +1,11 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public class SmartDebtResolverStrategy implements ResolverStrategy {
+ @Override
+ public void resolveBalanceSheet(BalanceSheet balanceSheet) {
+ // DO something
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/User.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/User.java
new file mode 100644
index 0000000..e65ebda
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/User.java
@@ -0,0 +1,32 @@
+package com.thealgorithm.splitwise;
+
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+/**
+ * @author: Subham Santra
+ */
+@Data
+@ToString(onlyExplicitlyIncluded = true)
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+public class User {
+ @EqualsAndHashCode.Include
+ @ToString.Include
+ private String name;
+ @ToString.Include
+ private List groups;
+ private PersonalBalanceSheet personalBalanceSheet;
+
+ public User(String name) {
+ this.name = name;
+ this.groups = new ArrayList<>();
+ this.personalBalanceSheet = new PersonalBalanceSheet();
+ }
+
+ public void add(Expense expense) {
+ // add new expense
+ }
+}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/UserIsNotPartOfGroupException.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/UserIsNotPartOfGroupException.java
new file mode 100644
index 0000000..6015894
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/UserIsNotPartOfGroupException.java
@@ -0,0 +1,6 @@
+package com.thealgorithm.splitwise;
+
+/**
+ * @author: Subham Santra
+ */
+public class UserIsNotPartOfGroupException extends Exception {}
diff --git a/low-level-design/src/main/java/com/thealgorithm/splitwise/UserSplit.java b/low-level-design/src/main/java/com/thealgorithm/splitwise/UserSplit.java
new file mode 100644
index 0000000..f341cee
--- /dev/null
+++ b/low-level-design/src/main/java/com/thealgorithm/splitwise/UserSplit.java
@@ -0,0 +1,14 @@
+package com.thealgorithm.splitwise;
+
+import lombok.Builder;
+import lombok.Value;
+
+/**
+ * @author: Subham Santra
+ */
+@Value
+@Builder
+public class UserSplit {
+ User user;
+ Double shareAmount;
+}
diff --git a/scripts/build_test.sh b/scripts/build_test.sh
new file mode 100755
index 0000000..d8348fb
--- /dev/null
+++ b/scripts/build_test.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env sh
+
+cd ../
+echo 'building TheAlgorithm'
+mvn clean
+mvn install
\ No newline at end of file