diff --git a/Bellman Ford/bellmanford using java/bellmanFord/PathFindingByBellmanFord.java b/Bellman Ford/bellmanford using java/bellmanFord/PathFindingByBellmanFord.java new file mode 100644 index 0000000..5a5f3a8 --- /dev/null +++ b/Bellman Ford/bellmanford using java/bellmanFord/PathFindingByBellmanFord.java @@ -0,0 +1,89 @@ +package bellmanFord; +import java.util.ArrayList; +import node.WeightedNode; + +public class PathFindingByBellmanFord { + + //Will store all the vertices + ArrayList nodeList = new ArrayList(); + + //Constructor + public PathFindingByBellmanFord(ArrayList nodeList) { + this.nodeList = nodeList; + for(WeightedNode aNode: nodeList){ + aNode.setDistance(Integer.MAX_VALUE/10); + } + }//end of method + + + // BellmanFord from a source node + void bellmanFord(WeightedNode sourceNode) { + sourceNode.setDistance(0); // set source distance to zero + + for (int i = 1; i < nodeList.size(); i++) { // repeat n-1 times + for (WeightedNode presentNode : nodeList) { // for each Vertex + for (WeightedNode neighbor : presentNode.getNeighbors()) { // for each Neighbor + // if distance of neighbor is greater than tentative new path then + // update distance of neighbor with new parent as presentNode + if (neighbor.getDistance() > (presentNode.getDistance() + presentNode.getWeightMap().get(neighbor))) { + neighbor.setDistance((presentNode.getDistance() + presentNode.getWeightMap().get(neighbor))); + neighbor.setParent(presentNode); + } + } // end of inner loop + } // end of mid loop + } // end of loop + + System.out.println("Checking for Negative Cycle ..."); + //for each edge check if update possible, if true then negative cycle is there report error + for(WeightedNode presentNode: nodeList) { + for(WeightedNode neighbor: presentNode.getNeighbors()) { + // if distance of neighbor is greater than tentative new path then we have a negative cycle, return from here.. + if(neighbor.getDistance() > (presentNode.getDistance()+presentNode.getWeightMap().get(neighbor))) { + System.out.println("Negative cycle found: \n"); + System.out.println("Vertex Name: " + neighbor.getName()); + System.out.println("Old Distance: " + neighbor.getDistance()); + int newDistance = presentNode.getDistance()+presentNode.getWeightMap().get(neighbor); + System.out.println("New distance: " + newDistance); + return; + } + } + }//end of loop + System.out.println("Negative cycle not found !"); + + + //Print table of node with minimum distance and shortest path from source + System.out.println("\n\nPrinting Paths now: "); + for (WeightedNode nodeToCheck : nodeList) { + if (nodeToCheck.getDistance() != Integer.MAX_VALUE / 10) { + System.out.print("Node " + nodeToCheck + ", distance: " + nodeToCheck.getDistance() + ", Path: "); + pathPrint(nodeToCheck); + } else { + System.out.print("No path for node " + nodeToCheck); + } + System.out.println(); + }//end of loop + }//end of method + + + //Printing path + private static void pathPrint(WeightedNode node) { + if(node.getParent()!=null) { + pathPrint(node.getParent()); + System.out.print("->"+node); + } + else + System.out.print(node); + }//end of method + + + // add a weighted edge between two nodes + public void addWeightedEdge(int i, int j, int d) { + WeightedNode first = nodeList.get(i-1); + WeightedNode second = nodeList.get(j-1); + first.getNeighbors().add(second); + first.getWeightMap().put(second,d); + }//end of method + +}//end of class + + diff --git a/Bellman Ford/bellmanford using java/bellmanFord/PathFindingByBellmanFordMain.java b/Bellman Ford/bellmanford using java/bellmanFord/PathFindingByBellmanFordMain.java new file mode 100644 index 0000000..ca35440 --- /dev/null +++ b/Bellman Ford/bellmanford using java/bellmanFord/PathFindingByBellmanFordMain.java @@ -0,0 +1,33 @@ +package bellmanFord; +import java.util.ArrayList; +import node.WeightedNode; + +public class PathFindingByBellmanFordMain { + + public static void main(String[] args) { + + ArrayList nodeList = new ArrayList<>(); + + //create 5 nodes: A,B,C,D,E + for(int i=0;i<5; i++) { + nodeList.add(new WeightedNode(""+(char)(65+i))); + } + + //Constructor + PathFindingByBellmanFord graph = new PathFindingByBellmanFord(nodeList); + + graph.addWeightedEdge(1,3,6); //Add A-> C , weight 6 + graph.addWeightedEdge(2,1,3); //Add B-> A , weight 3 + graph.addWeightedEdge(1,4,6); //Add A-> D , weight 6 + //graph.addWeightedEdge(1,4,-6); //Add A-> D , weight -6 TEST NEGATIVE WEIGHT HERE + graph.addWeightedEdge(4,3,1); //Add D-> C , weight 1 + graph.addWeightedEdge(3,4,2); //Add C-> D , weight 2 + graph.addWeightedEdge(4,2,1); //Add D-> B , weight 1 + graph.addWeightedEdge(5,4,2); //Add E-> D , weight 2 + graph.addWeightedEdge(5,2,4); //Add E-> B , weight 4 + + graph.bellmanFord(nodeList.get(4)); + + }//end of method + +}//end of class \ No newline at end of file diff --git a/Bellman Ford/bellmanford using java/node/BinaryNode.java b/Bellman Ford/bellmanford using java/node/BinaryNode.java new file mode 100644 index 0000000..4f3b3b0 --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/BinaryNode.java @@ -0,0 +1,46 @@ +package node; + +public class BinaryNode { + private int value; + private int height; + private BinaryNode left; + private BinaryNode right; + + public int getHeight() { + return height; + }//end of method + + public void setHeight(int height) { + this.height = height; + }//end of method + + public int getValue() { + return value; + }//end of method + + public void setValue(int value) { + this.value = value; + }//end of method + + public BinaryNode getLeft() { + return left; + }//end of method + + public void setLeft(BinaryNode left) { + this.left = left; + }//end of method + + public BinaryNode getRight() { + return right; + }//end of method + + public void setRight(BinaryNode right) { + this.right = right; + }//end of method + + @Override + public String toString() { + return value + ""; + }//end of method + +} diff --git a/Bellman Ford/bellmanford using java/node/BinaryNodeWithParent.java b/Bellman Ford/bellmanford using java/node/BinaryNodeWithParent.java new file mode 100644 index 0000000..b7deb76 --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/BinaryNodeWithParent.java @@ -0,0 +1,46 @@ +package node; + +public class BinaryNodeWithParent { + private int value; + private BinaryNodeWithParent parent; + private BinaryNodeWithParent left; + private BinaryNodeWithParent right; + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public BinaryNodeWithParent getParent() { + return parent; + } + + public void setParent(BinaryNodeWithParent parent) { + this.parent = parent; + } + + public BinaryNodeWithParent getLeft() { + return left; + } + + public void setLeft(BinaryNodeWithParent left) { + this.left = left; + } + + public BinaryNodeWithParent getRight() { + return right; + } + + public void setRight(BinaryNodeWithParent right) { + this.right = right; + } + + @Override + public String toString() { + return value+""; + } + +} diff --git a/Bellman Ford/bellmanford using java/node/DoubleNode.java b/Bellman Ford/bellmanford using java/node/DoubleNode.java new file mode 100644 index 0000000..0aa0dfe --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/DoubleNode.java @@ -0,0 +1,38 @@ +package node; + + +public class DoubleNode { + private int value; + private DoubleNode next; + private DoubleNode prev; + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public DoubleNode getNext() { + return next; + } + + public void setNext(DoubleNode next) { + this.next = next; + } + + public DoubleNode getPrev() { + return prev; + } + + public void setPrev(DoubleNode prev) { + this.prev = prev; + } + + @Override + public String toString() { + return value + ""; + } + +} diff --git a/Bellman Ford/bellmanford using java/node/GraphNode.java b/Bellman Ford/bellmanford using java/node/GraphNode.java new file mode 100644 index 0000000..7fbbe0f --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/GraphNode.java @@ -0,0 +1,66 @@ +package node; + +import java.util.*; + +public class GraphNode { + private String name; + private int index; //index is used to map this Node's name with index of Adjacency Matrix' cell# + private ArrayList neighbors = new ArrayList(); + private boolean isVisited = false; + private GraphNode parent; + + public GraphNode(String name, int index) { + this.name = name; + this.index = index; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public ArrayList getNeighbors() { + return neighbors; + } + + public void setNeighbors(ArrayList neighbors) { + this.neighbors = neighbors; + } + + public boolean isVisited() { + return isVisited; + } + + public void setVisited(boolean isVisited) { + this.isVisited = isVisited; + } + + public GraphNode getParent() { + return parent; + } + + public void setParent(GraphNode parent) { + this.parent = parent; + } + + public GraphNode(String name) { + this.name = name; + } + + @Override + public String toString() { + return name ; + } + +} diff --git a/Bellman Ford/bellmanford using java/node/NumberOfPathsNode.java b/Bellman Ford/bellmanford using java/node/NumberOfPathsNode.java new file mode 100644 index 0000000..4dbf4c8 --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/NumberOfPathsNode.java @@ -0,0 +1,112 @@ +package node; + +import java.util.ArrayList; + +public class NumberOfPathsNode { + + int costToReachLastCell = 0; + int costOfCurrentCell = 0; + NumberOfPathsNode rightCell = null; + NumberOfPathsNode downCell = null; + int numberOfWaysToComeHereFromRightOrDown = 0; + ArrayList NumberOfWaysSatifyingDownCell = new ArrayList(); + ArrayList NumberOfWaysSatifyingRightCell = new ArrayList(); + + + + //Constructor + public NumberOfPathsNode(int costOfCurrentCell, NumberOfPathsNode rightCell, NumberOfPathsNode DownCell, int costToReachLastCell) { + this.costOfCurrentCell = costOfCurrentCell; + this.rightCell = rightCell; + this.downCell = DownCell; + this.costToReachLastCell = costToReachLastCell; + } + + + + + //Getting numbers of ways to reach last cell from current cell + public int getnumberOfWaysToReachLastCellFromHere() { + int numberOfWaysToReachLastCellFromHere = 0; + for(int i=0; i= rightCell.costOfCurrentCell) { + NumberOfWaysSatifyingRightCell.add(rightCell.NumberOfWaysSatifyingRightCell.get(i)-rightCell.costOfCurrentCell); + } + }//end of loop + + for(int i=0; i= rightCell.costOfCurrentCell) { + NumberOfWaysSatifyingRightCell.add(rightCell.NumberOfWaysSatifyingDownCell.get(i)-rightCell.costOfCurrentCell); + } + }//end of loop + }//end of method + + + //Calculate number of ways to come here from Down cell + public void calculateNumberOfWaysSatifyingDownCell(){ + if((downCell == null) && (rightCell == null)) { //Base case for last row and col + NumberOfWaysSatifyingDownCell.add(costToReachLastCell); + } + + if(downCell == null) { + return; + } + + int sizeOfDownCellsRight = downCell.NumberOfWaysSatifyingRightCell.size(); + int sizeOfDownCellsDown = downCell.NumberOfWaysSatifyingDownCell.size(); + + for(int i=0; i= downCell.costOfCurrentCell) { + NumberOfWaysSatifyingDownCell.add(downCell.NumberOfWaysSatifyingRightCell.get(i)-downCell.costOfCurrentCell); + } + }//end of loop + + for(int i=0; i= downCell.costOfCurrentCell) { + NumberOfWaysSatifyingDownCell.add(downCell.NumberOfWaysSatifyingDownCell.get(i)-downCell.costOfCurrentCell); + } + }//end of loop + }//end of method + +}//end of class + diff --git a/Bellman Ford/bellmanford using java/node/SingleNode.java b/Bellman Ford/bellmanford using java/node/SingleNode.java new file mode 100644 index 0000000..cd6df09 --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/SingleNode.java @@ -0,0 +1,28 @@ +package node; + +public class SingleNode { + private int value; + private SingleNode next; + +public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public SingleNode getNext() { + return next; + } + + public void setNext(SingleNode next) { + this.next = next; + } + +@Override +public String toString() { + return value + ""; +} + +} diff --git a/Bellman Ford/bellmanford using java/node/WeightedNode.java b/Bellman Ford/bellmanford using java/node/WeightedNode.java new file mode 100644 index 0000000..60604e2 --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/WeightedNode.java @@ -0,0 +1,88 @@ +package node; + +import java.util.*; + +import mst.DisjointSet; + +public class WeightedNode implements Comparable { + public String name; + + private ArrayList neighbors = new ArrayList(); + private HashMap weightMap = new HashMap<>(); + private boolean isVisited = false; + private WeightedNode parent; + private int distance; + private DisjointSet set; //used in DisjointSet Algorithm + + public WeightedNode(String name) { + this.name = name; + distance = Integer.MAX_VALUE; + } + + public DisjointSet getSet() { + return set; + } + + public void setSet(DisjointSet set) { //used in DisjointSet Algorithm + this.set = set; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ArrayList getNeighbors() { + return neighbors; + } + + public void setNeighbors(ArrayList neighbors) { + this.neighbors = neighbors; + } + + public HashMap getWeightMap() { + return weightMap; + } + + public void setWeightMap(HashMap weightMap) { + this.weightMap = weightMap; + } + + public boolean isVisited() { + return isVisited; + } + + public void setVisited(boolean isVisited) { + this.isVisited = isVisited; + } + + public WeightedNode getParent() { + return parent; + } + + public void setParent(WeightedNode parent) { + this.parent = parent; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(WeightedNode o) { + return this.distance - o.distance; + } + +} diff --git a/Bellman Ford/bellmanford using java/node/WeightedNode2.java b/Bellman Ford/bellmanford using java/node/WeightedNode2.java new file mode 100644 index 0000000..7609072 --- /dev/null +++ b/Bellman Ford/bellmanford using java/node/WeightedNode2.java @@ -0,0 +1,88 @@ +package node; + +import java.util.*; + +import mst.DisjointSet; + +public class WeightedNode2 implements Comparable { + public String name; + + private ArrayList neighbors = new ArrayList(); + private HashMap weightMap = new HashMap<>(); + private boolean isVisited = false; + private WeightedNode2 parent; + private int distance; + private DisjointSet set; + + public WeightedNode2(String name) { + this.name = name; + distance = Integer.MAX_VALUE; + } + + public DisjointSet getSet() { + return set; + } + + public void setSet(DisjointSet set) { + this.set = set; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ArrayList getNeighbors() { + return neighbors; + } + + public void setNeighbors(ArrayList neighbors) { + this.neighbors = neighbors; + } + + public HashMap getWeightMap() { + return weightMap; + } + + public void setWeightMap(HashMap weightMap) { + this.weightMap = weightMap; + } + + public boolean isVisited() { + return isVisited; + } + + public void setVisited(boolean isVisited) { + this.isVisited = isVisited; + } + + public WeightedNode2 getParent() { + return parent; + } + + public void setParent(WeightedNode2 parent) { + this.parent = parent; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(WeightedNode2 o) { + return this.distance - o.distance; + } + +} diff --git a/Bellman Ford/bellmanford.cpp b/Bellman Ford/bellmanford.cpp new file mode 100644 index 0000000..c59fdc2 --- /dev/null +++ b/Bellman Ford/bellmanford.cpp @@ -0,0 +1,137 @@ +// A C++ program for Bellman-Ford's single source +// shortest path algorithm. +#include + +// a structure to represent a weighted edge in graph +struct Edge { + int src, dest, weight; +}; + +// a structure to represent a connected, directed and +// weighted graph +struct Graph { + // V-> Number of vertices, E-> Number of edges + int V, E; + + // graph is represented as an array of edges. + struct Edge* edge; +}; + +// Creates a graph with V vertices and E edges +struct Graph* createGraph(int V, int E) +{ + struct Graph* graph = new Graph; + graph->V = V; + graph->E = E; + graph->edge = new Edge[E]; + return graph; +} + +// A utility function used to print the solution +void printArr(int dist[], int n) +{ + printf("Vertex Distance from Source\n"); + for (int i = 0; i < n; ++i) + printf("%d \t\t %d\n", i, dist[i]); +} + +// The main function that finds shortest distances from src to +// all other vertices using Bellman-Ford algorithm. The function +// also detects negative weight cycle +void BellmanFord(struct Graph* graph, int src) +{ + int V = graph->V; + int E = graph->E; + int dist[V]; + + // Step 1: Initialize distances from src to all other vertices + // as INFINITE + for (int i = 0; i < V; i++) + dist[i] = INT_MAX; + dist[src] = 0; + + // Step 2: Relax all edges |V| - 1 times. A simple shortest + // path from src to any other vertex can have at-most |V| - 1 + // edges + for (int i = 1; i <= V - 1; i++) { + for (int j = 0; j < E; j++) { + int u = graph->edge[j].src; + int v = graph->edge[j].dest; + int weight = graph->edge[j].weight; + if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) + dist[v] = dist[u] + weight; + } + } + + // Step 3: check for negative-weight cycles. The above step + // guarantees shortest distances if graph doesn't contain + // negative weight cycle. If we get a shorter path, then there + // is a cycle. + for (int i = 0; i < E; i++) { + int u = graph->edge[i].src; + int v = graph->edge[i].dest; + int weight = graph->edge[i].weight; + if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) { + printf("Graph contains negative weight cycle"); + return; // If negative cycle is detected, simply return + } + } + + printArr(dist, V); + + return; +} + +// Driver program to test above functions +int main() +{ + /* Let us create the graph given in above example */ + int V = 5; // Number of vertices in graph + int E = 8; // Number of edges in graph + struct Graph* graph = createGraph(V, E); + + // add edge 0-1 (or A-B in above figure) + graph->edge[0].src = 0; + graph->edge[0].dest = 1; + graph->edge[0].weight = -1; + + // add edge 0-2 (or A-C in above figure) + graph->edge[1].src = 0; + graph->edge[1].dest = 2; + graph->edge[1].weight = 4; + + // add edge 1-2 (or B-C in above figure) + graph->edge[2].src = 1; + graph->edge[2].dest = 2; + graph->edge[2].weight = 3; + + // add edge 1-3 (or B-D in above figure) + graph->edge[3].src = 1; + graph->edge[3].dest = 3; + graph->edge[3].weight = 2; + + // add edge 1-4 (or A-E in above figure) + graph->edge[4].src = 1; + graph->edge[4].dest = 4; + graph->edge[4].weight = 2; + + // add edge 3-2 (or D-C in above figure) + graph->edge[5].src = 3; + graph->edge[5].dest = 2; + graph->edge[5].weight = 5; + + // add edge 3-1 (or D-B in above figure) + graph->edge[6].src = 3; + graph->edge[6].dest = 1; + graph->edge[6].weight = 1; + + // add edge 4-3 (or E-D in above figure) + graph->edge[7].src = 4; + graph->edge[7].dest = 3; + graph->edge[7].weight = -3; + + BellmanFord(graph, 0); + + return 0; +} + diff --git a/Prim's Algorithm/prim.cpp b/Prim's Algorithm/prim.cpp new file mode 100644 index 0000000..c3ed61e --- /dev/null +++ b/Prim's Algorithm/prim.cpp @@ -0,0 +1,93 @@ +#include +#include + +#define MAXINT 65356 + +using namespace std; + +int main() +{ + // input a graph where n indicate no. od vertices edges- no. of edges; + int n,edges; + + cout<<"Enter no. of vertices "; + cin>>n; + + cout<<"Enter no. of edges "; + cin>>edges; + + int x,y,w; // x,y vertex of edge , w- weight of edge. + + int** graph=new int*[n]; // stores graph. + + for(int i=0;i>x>>y>>w; + + graph[x-1][y-1]=w; + } + + int v; //starting vertex; + + cout<<"Enter starting vertex "; + cin>>v; + + int* dist=new int[n]; // distance keeps account the distance to reach non tree vertex from tree vertex. + int* parent=new int[n]; // keeps track of parent of each vertex. + bool* intree=new bool[n]; // keeps track which vertex is a tree vertex or non tree vertex. + + for(int i=1;i<=n;i++) + { + dist[i-1]=MAXINT; + parent[i-1]=-1; + intree[i-1]=false; + } + + dist[v-1]=0; // starting vertex distance will always be zero. + + // algorithm to construct tree each time will add one edge to while loop. + + while(!intree[v-1]) + { + int i=v-1; + intree[i]=true; + + for(int j=0;jgraph[i][j]) + { + dist[j]=graph[i][j]; + parent[j]=i; + } + } + } + + // to find which is the non tree vertex with minimum distance from the tree + + v=1; + int d=MAXINT; + + for(int i=0;i3/2) and for certain increments O(n4/3). For many practical variants, determining their time complexity remains an open problem. +### Bucket Sort +Bucket sort is a linear sorting algorithm.Bucket sort is one of the fastest sorting algorithms for numbers or strings of letter. It makes more space compared to other sorting techniques hence less preferable. The time complexity of Bucket sort is O(k*n).In the worst case scenario it can take O(n^2). + ### Binary Search @@ -122,11 +125,19 @@ Union: Join two subsets into a single subset. Union-Find Algorithm can be used to check whether an undirected graph contains cycle or not. Note that we have discussed an algorithm to detect cycle. This is another method based on Union-Find. This method assumes that the graph doesn’t contain any self-loops. +### Bellman Ford Algorithm +Given a graph and a source vertex src in graph, find shortest paths from src to all vertices in the given graph. The graph may contain negative weight edges. +We have discussed Dijkstra’s algorithm for this problem. Dijkstra’s algorithm is a Greedy algorithm and time complexity is O(VLogV) (with the use of Fibonacci heap). Dijkstra doesn’t work for Graphs with negative weight edges, Bellman-Ford works for such graphs. Bellman-Ford is also simpler than Dijkstra and suites well for distributed systems. But time complexity of Bellman-Ford is O(VE), which is more than Dijkstra. + + ### Kruskal's Algorithm (Minimum Spanning Tree) Kruskal's algorithm finds a minimum spanning forest of an undirected edge-weighted graph. If the graph is connected, it finds a minimum spanning tree. (A minimum spanning tree of a connected graph is a subset of the edges that forms a tree that includes every vertex, where the sum of the weights of all the edges in the tree is minimized. For a disconnected graph, a minimum spanning forest is composed of a minimum spanning tree for each connected component.) It is a greedy algorithm in graph theory as in each step it adds the next lowest-weight edge that will not form a cycle to the minimum spanning forest. [ALGORITHM](https://github.com/shubhdeep123/Algorithms/blob/kruskal/kruskalAlgo.md) +### Prim's Algorithm (Minimum Spanning Tree) +Like Kruskal’s algorithm, Prim’s algorithm is also a Greedy algorithm. It starts with an empty spanning tree. The idea is to maintain two sets of vertices. The first set contains the vertices already included in the MST, the other set contains the vertices not yet included. At every step, it considers all the edges that connect the two sets, and picks the minimum weight edge from these edges. After picking the edge, it moves the other endpoint of the edge to the set containing MST. + ### Topographical Sorting in a DAG (directed acyclic graph) Topological sort of a directed acyclic graph [DAG] is partial ordering of its nodes such that U < V implies there must not exist a path from V to U. @@ -141,3 +152,7 @@ Segment tree is a data structure that allows us to perform range queries and poi Given a directed graph, this program checks whether the graph conatins a cycle or not. The function returns true if the graph conatins at least one cycle , else returns false. Here we use DFS (Depth First Search) to detect the cycle.DFS for a connected graph produces a tree. There is a cycle in a graph only if there is a back edge present in the graph. A back edge is an edge that is from a node to itself (self-loop) or one of its ancestors in the tree produced by DFS. [ALGORITHM](CycleDetectionDirectedGraph.cpp). for more info check out [this](https://www.geeksforgeeks.org/detect-cycle-in-a-graph/). + +### Sweep Line Algorithm +The algorithm first sorts the end points along the x axis from left to right, then it passes a vertical line through all points from left to right and checks for intersections. The first step is sorting which takes O(nLogn) time. The second step process 2n points and for processing every point, it takes O(Logn) time. Therefore, overall time complexity is O(nLogn). + diff --git a/Sorting Algos & Problems/bucketSort.cpp b/Sorting Algos & Problems/bucketSort.cpp new file mode 100644 index 0000000..4efba16 --- /dev/null +++ b/Sorting Algos & Problems/bucketSort.cpp @@ -0,0 +1,42 @@ +// C++ program to sort an array using bucket sort +#include +#include +#include +using namespace std; + +// Function to sort arr[] of size n using bucket sort +void bucketSort(float arr[], int n) +{ + // 1) Create n empty buckets + vector b[n]; + + // 2) Put array elements in different buckets + for (int i = 0; i < n; i++) { + int bi = n * arr[i]; // Index in bucket + b[bi].push_back(arr[i]); + } + + // 3) Sort individual buckets + for (int i = 0; i < n; i++) + sort(b[i].begin(), b[i].end()); + + // 4) Concatenate all buckets into arr[] + int index = 0; + for (int i = 0; i < n; i++) + for (int j = 0; j < b[i].size(); j++) + arr[index++] = b[i][j]; +} + +/* Driver program to test above function */ +int main() +{ + float arr[] = { 0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434 }; + int n = sizeof(arr) / sizeof(arr[0]); + bucketSort(arr, n); + + cout << "Sorted array is \n"; + for (int i = 0; i < n; i++) + cout << arr[i] << " "; + return 0; +} + diff --git a/Sweep Line Algorithm/sweep.cpp b/Sweep Line Algorithm/sweep.cpp new file mode 100644 index 0000000..509ebd2 --- /dev/null +++ b/Sweep Line Algorithm/sweep.cpp @@ -0,0 +1,289 @@ +#include +#include +#include +#include + +struct Point +{ + char letter; + double x, y; + Point & operator = (Point const & b) { letter = b.letter; x = b.x; y = b.y; return *this; } + Point(const Point & b) : letter(b.letter), x(b.x), y(b.y) {} + Point(char _letter, double _x, double _y) : letter(_letter), x(_x), y(_y) {} + bool operator <(const Point & b) const + { + if (y < b.y - 1.0e-9) return true; + else if (y > b.y + 1.0e-9) return false; + else if (x < b.x - 1.0e-9) return true; + else return false; + } + bool operator ==(const Point & b) const + { + return fabs(y - b.y) < 1.0e-9 && fabs(x - b.x) < 1.0e-9; + } + bool operator !=(const Point & b) const + { + return fabs(y - b.y) > 1.0e-9 || fabs(x - b.x) > 1.0e-9; + } +}; + +struct Segment +{ + Point beg, end; + Segment & operator = (Segment const & b) { beg = b.beg; end = b.end; return *this; } + Segment(const Segment & b) : beg(b.beg), end(b.end) {} + Segment(const Point & _beg, const Point & _end) : beg(_beg), end(_end) {} +}; + +#define SEG_START 0 +#define SEG_END 1 + +class event_less +{ +public: + bool operator()(const std::pair & a, const std::pair & b) const + { + if (a.first < b.first - 1.0e-9) + return true; + else if (a.first > b.first + 1.0e-9) + return false; + else if (a.second < b.second) + return true; + return false; + } +}; + + + + +std::pair intersect(const Segment & a, const Segment & b, bool print) +{ + Point ret('a', 0, 0); + double div = (a.beg.x - a.end.x)*(b.beg.y - b.end.y) - (a.beg.y - a.end.y)*(b.beg.x - b.end.x), t; + if (fabs(div) < 1.0e-13) + { + if (print) std::cout << "divisor is zero" << std::endl; + return std::make_pair(false, ret); + } + ret.x = ((a.beg.x*a.end.y - a.beg.y*a.end.x)*(b.beg.x - b.end.x) - (a.beg.x - a.end.x)*(b.beg.x*b.end.y - b.beg.y*b.end.x)) / div; + ret.y = ((a.beg.x*a.end.y - a.beg.y*a.end.x)*(b.beg.y - b.end.y) - (a.beg.y - a.end.y)*(b.beg.x*b.end.y - b.beg.y*b.end.x)) / div; + if (print) std::cout << "found (" << ret.x << "," << ret.y << ")" << std::endl; + //probably some of these tests are redundant + if (fabs(a.end.x - a.beg.x) > 1.0e-9) + { + t = (ret.x - a.beg.x) / (a.end.x - a.beg.x); + if (t < 1.0e-9 || t > 1.0 - 1.0e-9) { if (print) std::cout << "out of bound: " << t << std::endl; return std::make_pair(false, ret); } + } + if (fabs(a.end.y - a.beg.y) > 1.0e-9) + { + t = (ret.y - a.beg.y) / (a.end.y - a.beg.y); + if (t < 1.0e-9 || t > 1.0 - 1.0e-9) { if (print) std::cout << "out of bound: " << t << std::endl; return std::make_pair(false, ret); } + } + if (fabs(b.end.x - b.beg.x) > 1.0e-9) + { + t = (ret.x - b.beg.x) / (b.end.x - b.beg.x); + if (t < 1.0e-9 || t > 1.0 - 1.0e-9) { if (print) std::cout << "out of bound: " << t << std::endl; return std::make_pair(false, ret); } + } + if (fabs(b.end.y - b.beg.y) > 1.0e-9) + { + t = (ret.y - b.beg.y) / (b.end.y - b.beg.y); + if (t < 1.0e-9 || t > 1.0 - 1.0e-9) { if (print) std::cout << "out of bound: " << t << std::endl; return std::make_pair(false, ret); } + } + if (print) std::cout << "intersection accepted" << std::endl; + return std::make_pair(true, ret); +} + +void intersect(int a, int b, const Point & I, std::vector & segments, std::multimap & sweep, std::multimap, int,event_less> & events, bool print) +{ + //remove event of ending of old segment + { + int rem_end_events[2]; + rem_end_events[0] = a; + rem_end_events[1] = b; + for (int k = 0; k < 2; ++k) + { + std::pair< std::multimap, int,event_less>::iterator, std::multimap,int,event_less>::iterator > del = events.equal_range(std::make_pair(segments[rem_end_events[k]].end.x,SEG_END)); //get all events at position of the end + bool flag = false; + for (std::multimap, int,event_less>::iterator it = del.first; it != del.second; ++it) //search over all events + { + if (it->first.second == SEG_END && it->second == rem_end_events[k]) //event is end of segment and segment matches current + { + events.erase(it); //remove that segment + flag = true; + break; //do not expect any more + } + } + if (!flag) std::cout << "Cannot find proper ending event for segment" << std::endl; + } + } + //add new segment with intersection point up to end + segments.push_back(Segment(I, segments[a].end)); + //add event of starting of new segment + events.insert(std::make_pair(std::make_pair(I.x,SEG_START), (int)segments.size() - 1)); + //add event of ending of new segment + events.insert(std::make_pair(std::make_pair(segments.back().end.x,SEG_END),(int)segments.size() - 1)); + //change ending point for current segment + segments[a].end = I; + //add event of ending of old segment + events.insert(std::make_pair(std::make_pair(I.x,SEG_END), a)); + //add new segment with intersection point up to end + segments.push_back(Segment(I, segments[b].end)); + //add event of starting of new segment + events.insert(std::make_pair(std::make_pair(I.x,SEG_START), (int)segments.size() - 1)); + //add event of ending of new segment + events.insert(std::make_pair(std::make_pair(segments.back().end.x,SEG_END), (int)segments.size() - 1)); + //change ending point for current segment + segments[b].end = I; + //add event of ending of old segment + events.insert(std::make_pair(std::make_pair(I.x,SEG_END), b)); + if (print) + { + std::cout << "Number of events: " << events.size() << std::endl; + for (std::multimap, int,event_less>::iterator it = events.begin(); it != events.end(); ++it) + std::cout << "x: " << it->first.first << " type " << (it->first.second == SEG_START ? "start" : "end") << " segment " << it->second << std::endl; + } +} + +//find all intersection points +void intersect(std::vector & segments, std::vector & intersections, bool print) +{ + std::multimap,int,event_less> events; + std::multimap sweep; + + if( print ) + { + std::cout << "Input segments[" << segments.size() << "]: " << std::endl; + for (std::vector::iterator it = segments.begin(); it != segments.end(); ++it) + std::cout << "[ " << it->beg.letter << "(" << it->beg.x << "," << it->beg.y << "), " << it->end.letter << "(" << it->end.x << "," << it->end.y << ") ] " << std::endl; + std::cout << "Create events based on segments." << std::endl; + } + + for (int k = 0; k < (int)segments.size(); ++k) + { + if (segments[k].beg.x > segments[k].end.x) + std::swap(segments[k].beg, segments[k].end); + events.insert(std::make_pair(std::make_pair(segments[k].beg.x,SEG_START),k)); + events.insert(std::make_pair(std::make_pair(segments[k].end.x,SEG_END), k)); + } + + + if (print) + { + std::cout << "Number of events: " << events.size() << std::endl; + for (std::multimap, int,event_less>::iterator it = events.begin(); it != events.end(); ++it) + std::cout << "x: " << it->first.first << " type " << (it->first.second == SEG_START ? "start" : "end") << " segment " << it->second << std::endl; + + std::cout << " Start parsing events" << std::endl; + } + + while (!events.empty()) + { + std::multimap,int,event_less>::iterator first = events.begin(); + int t = first->first.second; + int s = first->second; + events.erase(first); + if (t == SEG_START) + { + if( print ) std::cout << "Segment " << s << " start" << std::endl; + //check if there is a line with same position + std::multimap::iterator ins = sweep.insert(std::make_pair(segments[s].beg, s)); + if (print) + { + std::cout << "Inserted into sweep" << std::endl; + for (std::multimap::iterator it = sweep.begin(); it != sweep.end(); ++it) + std::cout << it->first.letter << "(" << it->first.x << "," << it->first.y << ")" << " segment " << it->second << std::endl; + } + //check line (or lines above current) + for (int dir = 0; dir <= 1; ++dir) // look up or down + { + if( print ) std::cout << "Looking " << (dir ? "up" : "down") << std::endl; + std::multimap::iterator iter = ins; + while ((dir ? ++iter : iter--) != (dir ? sweep.end() : sweep.begin())) //y is greater for next + { + if (print) std::cout << "test " << s << " with " << iter->second << std::endl; + if (segments[s].beg != segments[iter->second].beg) //ignore same starting position + { + if (print) std::cout << "checking intersection" << std::endl; + std::pair I = intersect(segments[s], segments[iter->second],print); + if (I.first) + { + I.second.letter += (char)intersections.size(); + if( print ) std::cout << "Intersection of " << s << " and " << iter->second << " at " << I.second.letter << "(" << I.second.x << "," << I.second.y << ")" << std::endl; + intersections.push_back(I.second); + intersect(s, iter->second, I.second, segments, sweep, events,print); + } + } + else if (print) std::cout << "skipping segments with same starting point" << std::endl; + if ((2*dir-1)*(iter->first.y - ins->first.y) > 0) //visited line is above (below) current + break; //stop search + } + } + } + else if (t == SEG_END) + { + if( print ) std::cout << "Segment " << s << " end" << std::endl; + //remove segment from sweep + std::pair< std::multimap::iterator, std::multimap::iterator > range = sweep.equal_range(segments[s].beg); + if( print ) std::cout << "Range distance " << std::distance(range.first,range.second) << " sweep size " << sweep.size() << std::endl; + std::multimap::iterator above = range.second, below = range.first; + bool flag = false, test = true; + if( below-- == sweep.begin() ) test = false; + if( above == sweep.end() ) test = false; + if( test && print ) std::cout << "Test will be performed" << std::endl; + for (std::multimap::iterator it = range.first; it != range.second; ++it) //search over all events + { + if( it->second == s) //found necessery segment + { + if (print) + { + std::cout << "Erase segment " << s << " from sweep: " << std::endl; + for (std::multimap::iterator it = sweep.begin(); it != sweep.end(); ++it) + std::cout << it->first.letter << "(" << it->first.x << "," << it->first.y << ")" << " segment " << it->second << std::endl; + } + sweep.erase(it); + flag = true; + break; //do not expect any more + } + } + if (!flag) std::cout << __FILE__ << ":" << __LINE__ << " Error: cannot find segment " << s << " in sweep" << std::endl; + if (test) + { + if (print) std::cout << "test " << below->second << " with " << above->second << std::endl; + if (segments[above->second].beg != segments[below->second].beg) + { + if (print) std::cout << "checking intersection" << std::endl; + std::pair I = intersect(segments[below->second], segments[above->second],print); + if (I.first) + { + I.second.letter += (char)intersections.size(); + if( print ) std::cout << "Intersection of " << below->second << " and " << above->second << " at " << I.second.letter << "(" << I.second.x << "," << I.second.y << ")" << std::endl; + intersections.push_back(I.second); + intersect(below->second, above->second, I.second, segments, sweep, events,print); + } + } + else if (print) std::cout << "skipping segments with same starting point" << std::endl; + } + } + } + +} + + +int main() +{ + std::vector intersections; + std::vector segments; + segments.push_back(Segment(Point('A',-7.41, -0.58), Point('C',-1.3,-0.79))); + segments.push_back(Segment(Point('B',-4.0, 1.27), Point('D',-4.21, -2.99))); + segments.push_back(Segment(Point('F',-4.92, 0.71), Point('G',-4.26, -1.40))); + segments.push_back(Segment(Point('I',-4.55, -1.24), Point('J',-2.54, -0.42))); + segments.push_back(Segment(Point('K',-3.70, 0.48), Point('L',-3.70, -2.41))); //vertical + intersect(segments, intersections,false); + std::cout << "Intersection points[" << intersections.size() << "]: " << std::endl; + for (std::vector::iterator it = intersections.begin(); it != intersections.end(); ++it) + std::cout << it->letter << "(" << it->x << "," << it->y << ") " << std::endl; + std::cout << "Segments[" << segments.size() << "]: " << std::endl; + for (std::vector::iterator it = segments.begin(); it != segments.end(); ++it) + std::cout << "[ " << it->beg.letter << "(" << it->beg.x << "," << it->beg.y << "), " << it->end.letter << "(" << it->end.x << "," << it->end.y << ") ] " << std::endl; + return 0; +} diff --git a/leetcode-problems/0001_two_sum.py b/leetcode-problems/0001_two_sum.py new file mode 100644 index 0000000..1e758cf --- /dev/null +++ b/leetcode-problems/0001_two_sum.py @@ -0,0 +1,34 @@ +""" +Given an array of integers, return indices of the two numbers such that they add up to a specific target. +You may assume that each input would have exactly one solution, and you may not use the same element twice. + +Example: +Given nums = [2, 7, 11, 15], target = 9, +Because nums[0] + nums[1] = 2 + 7 = 9, +return [0, 1]. +""" + + +class Solution: + # Time: O(n^2), Space: O(n)?? + def two_sum_brute_force(self, nums, target): + return [[i, j] for i in range(len(nums)) for j in range(i+1, len(nums), 1) if nums[i] + nums[j] == target][0] + + # Time: O(n), Space: O(n) + def two_sum_hash(self, nums, target): + d = {} + for index, num in enumerate(nums): + if d.get(num) is None: + d[target - num] = index + else: + return [d.get(num), index] + return -1, -1 + + +if __name__ == "__main__": + nums = [2, 7, 11, 15] + target = 9 + res1 = Solution().two_sum_brute_force(nums, target) + res2 = Solution().two_sum_hash(nums, target) + + print(res1, res2) diff --git a/leetcode-problems/0007_reverse_integer.py b/leetcode-problems/0007_reverse_integer.py new file mode 100644 index 0000000..74c9739 --- /dev/null +++ b/leetcode-problems/0007_reverse_integer.py @@ -0,0 +1,23 @@ +class Solution: + def reverse(self, x: int) -> int: + x = int(str(x)[::-1]) if x >= 0 else - int(str(-x)[::-1]) + return x if x < 2147483648 and x >= -2147483648 else 0 + + def reverse2(self, x: int) -> int: + ans = 0 + if x < 0: + sign = -1 + x = -x + else: + sign = 1 + + while x != 0: + pop = x % 10 + x //= 10 + ans = ans * 10 + pop + # print(f"pop: {pop} x: {x} rev: {ans}") + + if -2**31 <= ans <= 2**31 - 1: + return ans * sign + else: + return 0 diff --git a/leetcode-problems/0009_palindrome_number.py b/leetcode-problems/0009_palindrome_number.py new file mode 100644 index 0000000..dbbd3b8 --- /dev/null +++ b/leetcode-problems/0009_palindrome_number.py @@ -0,0 +1,17 @@ +class Solution: + def isPalindrome(self, x: int) -> bool: + if x < 0: + return False + x_copy = x + rev = 0 + while x > 0: + pop = x % 10 + x //= 10 + rev = rev * 10 + pop + return x_copy == rev + + +if __name__ == "__main__": + sol = Solution() + result = sol.isPalindrome(121) + print(result) diff --git a/leetcode-problems/0011_container_with_most_water.py b/leetcode-problems/0011_container_with_most_water.py new file mode 100644 index 0000000..fe4a748 --- /dev/null +++ b/leetcode-problems/0011_container_with_most_water.py @@ -0,0 +1,18 @@ +class Solution: + def maxArea(self, height): + max_area = 0 + i, j = 0, len(height) - 1 + while i < j: + max_area = max(max_area, (j - i) * min(height[i], height[j])) + if height[i] < height[j]: + i += 1 + else: + j -= 1 + return max_area + + +if __name__ == "__main__": + sol = Solution() + height = [1, 8, 6, 2, 5, 4, 8, 3, 7] + result = sol.maxArea(height) + print(result) diff --git a/leetcode-problems/0013_roman_to_integer.py b/leetcode-problems/0013_roman_to_integer.py new file mode 100644 index 0000000..b8891e2 --- /dev/null +++ b/leetcode-problems/0013_roman_to_integer.py @@ -0,0 +1,92 @@ +""" +Approach 1: Left-to-Right Pass: T: O(1), S: O(1) +Approach 2: Left-to-Right Pass Improved: T: O(1), S: O(1) +Approach 3: Right-to-Left Pass + +""" +# approach - 1 +values1 = { + "I": 1, + "V": 5, + "X": 10, + "L": 50, + "C": 100, + "D": 500, + "M": 1000, +} + +# approach - 2 +values2 = { + "I": 1, + "V": 5, + "X": 10, + "L": 50, + "C": 100, + "D": 500, + "M": 1000, + "IV": 4, + "IX": 9, + "XL": 40, + "XC": 90, + "CD": 400, + "CM": 900 +} + + +class Solution: + # approach 1 + def romanToInt1(self, s: str) -> int: + total = 0 + i = 0 + while i < len(s): + # If this is the subtractive case. + if i + 1 < len(s) and values1[s[i]] < values1[s[i + 1]]: + total += values1[s[i + 1]] - values1[s[i]] + i += 2 + # Else this is NOT the subtractive case. + else: + total += values1[s[i]] + i += 1 + return total + + # approach - 2 + def romanToInt2(self, s: str) -> int: + total = 0 + i = 0 + while i < len(s): + # This is the subtractive case. + if i < len(s) - 1 and s[i:i + 2] in values2: + total += values2[s[i:i + 2]] + i += 2 + else: + total += values2[s[i]] + i += 1 + return total + + # approach - 3 + def romanToInt(self, s: str) -> int: + total = values1.get(s[-1]) + for i in reversed(range(len(s) - 1)): + if values1[s[i]] < values1[s[i + 1]]: + total -= values1[s[i]] + else: + total += values1[s[i]] + return total + + def romanToInt4(self, s: str) -> int: + roman_value_dict = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + subtraction_dict = {'IV': 4, 'IX': 9, + 'XL': 40, 'XC': 90, + 'CD': 400, 'CM': 900} + int_value = 0 + for k, v in subtraction_dict.items(): + while k in s: + s_index = s.find(k) + s = s[:s_index] + s[s_index + 2:] + int_value = int_value + v + # print(s) + + for char in s: + int_value = int_value + roman_value_dict[char] + + return int_value diff --git a/leetcode-problems/0014_longest_common_prefix.py b/leetcode-problems/0014_longest_common_prefix.py new file mode 100644 index 0000000..2dcbba2 --- /dev/null +++ b/leetcode-problems/0014_longest_common_prefix.py @@ -0,0 +1,30 @@ +class Solution: + def longestCommonPrefix(self, strs: List[str]) -> str: + if len(strs) > 0: + sorted_str_list = sorted(strs, key=lambda x: len(x)) + max_count = len(sorted_str_list[0]) + temp_list = [] + final_str_list = [] + final_str = "" + count = 0 + for count in range(0, max_count, 1): + for word in sorted_str_list: + temp_list.append(word[count]) + if temp_list.count(temp_list[0]) == len(temp_list): + final_str_list.append(temp_list[0]) + temp_list = [] + continue + else: + break + + if len(final_str_list) != 0: + final_str = final_str.join(final_str_list) + return final_str + # print(final_str) + else: + return "" + # print("") + else: + return "" + # print("") + diff --git a/leetcode-problems/0020_valid_parentheses.py b/leetcode-problems/0020_valid_parentheses.py new file mode 100644 index 0000000..7a4e1f8 --- /dev/null +++ b/leetcode-problems/0020_valid_parentheses.py @@ -0,0 +1,19 @@ +class Solution: + def isValid(self, s: str) -> bool: + map_dict = { + ')': '(', + ']': '[', + '}': '{', + } + stack = [] + for char in s: + if not char in map_dict: + stack.append(char) + else: + top = stack.pop() if stack else '#' + if map_dict[char] != top: + return False + + return not stack + + \ No newline at end of file diff --git a/leetcode-problems/0035_search_insert_position.py b/leetcode-problems/0035_search_insert_position.py new file mode 100644 index 0000000..c2ef0ec --- /dev/null +++ b/leetcode-problems/0035_search_insert_position.py @@ -0,0 +1,18 @@ +""" +Approach 1: Binary Search + +""" +class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + l, r = 0, len(nums) - 1 + while l <= r: + mid = (l + r) >> 1 + if target < nums[mid]: + r = mid - 1 + elif target == nums[mid]: + return mid + else: + l = mid + 1 + + # print("mid: {} l: {} r: {}".format(mid, l, r)) + return l \ No newline at end of file diff --git a/leetcode-problems/0042_trapping_rain_water.py b/leetcode-problems/0042_trapping_rain_water.py new file mode 100644 index 0000000..1b2f724 --- /dev/null +++ b/leetcode-problems/0042_trapping_rain_water.py @@ -0,0 +1,28 @@ +class Solution: + def trap(self, height): + size = len(height) + if size < 3: + return 0 + + total_water = 0 + i, j = 0, len(height) - 1 + l_max, r_max = height[0], height[-1] + + while i <= j: + l_max, r_max = max(l_max, height[i]), max(r_max, height[j]) + + if l_max <= r_max: + total_water += (l_max - height[i]) + i += 1 + else: + total_water += (r_max - height[j]) + j -= 1 + + return total_water + + +if __name__ == "__main__": + sol = Solution() + h = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1] + result = sol.trap(h) + print(result) diff --git a/leetcode-problems/0053_maximum_subarray.py b/leetcode-problems/0053_maximum_subarray.py new file mode 100644 index 0000000..50ac3c4 --- /dev/null +++ b/leetcode-problems/0053_maximum_subarray.py @@ -0,0 +1,78 @@ +""" +Approach 1: Divide and Conquer +- O(N), O(log n) + +Approach 2: Greedy +- O(N), O(1) + +Approach 3: Dynamic Programming (Kadane's algorithm) +- O(N), O(1) +""" + + +class Solution: + def cross_sum(self, nums, left, right, p): + if left == right: + return nums[left] + + left_subsum = float('-inf') + curr_sum = 0 + for i in range(p, left - 1, -1): + curr_sum += nums[i] + left_subsum = max(left_subsum, curr_sum) + + right_subsum = float('-inf') + curr_sum = 0 + for i in range(p + 1, right + 1): + curr_sum += nums[i] + right_subsum = max(right_subsum, curr_sum) + + return left_subsum + right_subsum + + def helper(self, nums, left, right): + if left == right: + return nums[left] + + p = (left + right) // 2 + + left_sum = self.helper(nums, left, p) + right_sum = self.helper(nums, p + 1, right) + cross_sum = self.cross_sum(nums, left, right, p) + + return max(left_sum, right_sum, cross_sum) + + def maxSubArray1(self, nums): + return self.helper(nums, 0, len(nums) - 1) + + def maxSubArray2(self, nums: List[int]) -> int: + n = len(nums) + curr_sum = nums[0] + max_sum = nums[0] + for i in range(1, n): + curr_sum = max(curr_sum + nums[i], nums[i]) + max_sum = max(max_sum, curr_sum) + + return max_sum + + def maxSubArray3(self, nums: List[int]) -> int: + n = len(nums) + # curr_sum = nums[0] + max_sum = nums[0] + for i in range(1, n): + if nums[i - 1] > 0: + nums[i] += nums[i - 1] + max_sum = max(max_sum, nums[i]) + + return max_sum + + def maxSubArray_1(self, nums: List[int]) -> int: + for i in range(1, len(nums)): + nums[i] = max(nums[i], nums[i - 1] + nums[i]) + return max(nums) + + +if __name__ == "__main__": + sol = Solution() + nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] + result = sol.maxSubArray1(nums) + print(result) diff --git a/leetcode-problems/0054_spiral_matrix.py b/leetcode-problems/0054_spiral_matrix.py new file mode 100644 index 0000000..67528a4 --- /dev/null +++ b/leetcode-problems/0054_spiral_matrix.py @@ -0,0 +1,28 @@ +class Solution: + def spiralOrder(self, matrix): + if not matrix: return [] + R, C = len(matrix), len(matrix[0]) + visited = [[False] * C for _ in range(R)] + dr = [0, 1, 0, -1] + dc = [1, 0, -1, 0] + ans = [] + x = y = di = 0 + for _ in range(R * C): + ans.append(matrix[x][y]) + visited[x][y] = True + + cx, cy = x + dr[di], y + dc[di] + if 0 <= cx < R and 0 <= cy < C and not visited[cx][cy]: + x, y = cx, cy + else: + di = (di + 1) % 4 + x, y = x + dr[di], y + dc[di] + + return ans + + +if __name__ == "__main__": + sol = Solution() + mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + result = sol.spiralOrder(mat) + print(result) diff --git a/leetcode-problems/0064_minimum_path_sum.py b/leetcode-problems/0064_minimum_path_sum.py new file mode 100644 index 0000000..2105a4b --- /dev/null +++ b/leetcode-problems/0064_minimum_path_sum.py @@ -0,0 +1,34 @@ +""" + +cost(i,j)=grid[i][j]+min(cost(i+1,j),cost(i,j+1)) + +Approach 1: Brute Force +- T: O(2^(m+n)) S: O(m+n) + +Approach 2: Dynamic Programming 2D +- dp(i,j)=grid(i,j)+min(dp(i+1,j),dp(i,j+1)) +- T: O(mn), S:O(mn) + +Approach 3: Dynamic Programming 1D +- dp(j)=grid(i,j)+min(dp(j),dp(j+1)) +- T: O(mn), S:O(n) + +Approach 4: Dynamic Programming (Without Extra Space) +- grid(i,j)=grid(i,j)+min(grid(i+1,j),grid(i,j+1)) +- T: O(mn), S:O(1) + +""" +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + r, c = len(grid), len(grid[0]) + for i in range(1, r): + grid[i][0] += grid[i-1][0] + + for i in range(1, c): + grid[0][i] += grid[0][i-1] + + for i in range(1, r): + for j in range(1, c): + grid[i][j] += min(grid[i-1][j], grid[i][j-1]) + + return grid[-1][-1] \ No newline at end of file diff --git a/leetcode-problems/0066_plus_one.py b/leetcode-problems/0066_plus_one.py new file mode 100644 index 0000000..8f8a48b --- /dev/null +++ b/leetcode-problems/0066_plus_one.py @@ -0,0 +1,37 @@ +""" +Approach 1: Schoolbook Addition with Carry +- T: O(n), S: O(n) {O(1): when digits contains at least one not-nine digit} +""" +class Solution: + # approach-1 + def plusOne1(self, digits: List[int]) -> List[int]: + n = len(digits) + + # move along the input array starting from the end + for i in range(n): + idx = n - 1 - i + # set all the nines at the end of array to zeros + if digits[idx] == 9: + digits[idx] = 0 + # here we have the rightmost not-nine + else: + # increase this rightmost not-nine by 1 + digits[idx] += 1 + # and the job is done + return digits + + # we're here because all the digits are nines + return [1] + digits + + def plusOne(self, digits): + num = 0 + for i in range(len(digits)): + num += digits[i] * pow(10, (len(digits) - 1 - i)) + return [int(i) for i in str(num + 1)] + + +if __name__ == "__main__": + sol = Solution() + digits = [4, 3, 2, 1] + result = sol.plusOne(digits) + print(result) diff --git a/leetcode-problems/0069_sqrt_x.py b/leetcode-problems/0069_sqrt_x.py new file mode 100644 index 0000000..da001e1 --- /dev/null +++ b/leetcode-problems/0069_sqrt_x.py @@ -0,0 +1,62 @@ +from math import e, log +""" +Approach 1: Pocket Calculator Algorithm +- O(1), O(1) + +Approach 2: Binary Search +- O(log n), O(1) + +Approach 3: Recursion + Bit Shifts +- O(log n), O(log n) + +Approach 4: Newton's Method +- O(log n), O(1) +""" +class Solution: + # approach - 1 + def mySqrt1(self, x): + if x < 2: + return x + + left = int(e ** (0.5 * log(x))) + right = left + 1 + return left if right * right > x else right + + # approach 2 + def mySqrt2(self, x): + if x < 2: + return x + + left, right = 2, x // 2 + + while left <= right: + pivot = left + (right - left) // 2 + num = pivot * pivot + if num > x: + right = pivot - 1 + elif num < x: + left = pivot + 1 + else: + return pivot + + return right + + def mySqrt3(self, x): + if x < 2: + return x + + left = self.mySqrt3(x >> 2) << 1 + right = left + 1 + return left if right * right > x else right + + def mySqrt4(self, x): + if x < 2: + return x + + x0 = x + x1 = (x0 + x / x0) / 2 + while abs(x0 - x1) >= 1: + x0 = x1 + x1 = (x0 + x / x0) / 2 + + return int(x1) diff --git a/leetcode-problems/0070_climbing_stairs.py b/leetcode-problems/0070_climbing_stairs.py new file mode 100644 index 0000000..d072a57 --- /dev/null +++ b/leetcode-problems/0070_climbing_stairs.py @@ -0,0 +1,19 @@ +class Solution: + def climbStairs(self, n: int) -> int: + if n == 1: + return 1 + f = [None] * (n + 1) + f[1] = 1 + f[2] = 2 + + for i in range(3, n + 1): + f[i] = f[i - 1] + f[i - 2] + + return f[n] + + +if __name__ == "__main__": + sol = Solution() + n = 3 + result = sol.climbStairs(n) + print(result) diff --git a/leetcode-problems/0074_search_a_2d_matrix.py b/leetcode-problems/0074_search_a_2d_matrix.py new file mode 100644 index 0000000..3e0ebd8 --- /dev/null +++ b/leetcode-problems/0074_search_a_2d_matrix.py @@ -0,0 +1,39 @@ +""" +Approach 1: Binary search +- O(log m*n), O(1) +""" +class Solution: + # approach - 1 + def searchMatrix1(self, matrix: List[List[int]], target: int) -> bool: + m = len(matrix) + if m == 0: + return False + n = len(matrix[0]) + + # binary search + left, right = 0, m * n - 1 + while left <= right: + pivot_idx = (left + right) // 2 + pivot_element = matrix[pivot_idx // n][pivot_idx % n] + if target == pivot_element: + return True + else: + if target < pivot_element: + right = pivot_idx - 1 + else: + left = pivot_idx + 1 + return False + + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix: return False + + R, C = len(matrix), len(matrix[0]) + cr, cc = 0, C - 1 + while cr < R and cc >= 0: + if matrix[cr][cc] == target: + return True + elif matrix[cr][cc] > target: + cc -= 1 + elif matrix[cr][cc] < target: + cr += 1 + \ No newline at end of file diff --git a/leetcode-problems/0100_same_tree.py b/leetcode-problems/0100_same_tree.py new file mode 100644 index 0000000..a112449 --- /dev/null +++ b/leetcode-problems/0100_same_tree.py @@ -0,0 +1,26 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right + +class Solution: + def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: + q1, q2 = collections.deque([p]), collections.deque([q]) + while q1 and q2: + n1, n2 = q1.popleft(), q2.popleft() + + if not n1 and not n2: + return True + if not n1 or not n2: + return False + if n1.val != n2.val: + return False + + if n1 and n2: + q1.append(n1.left) + q1.append(n1.right) + q2.append(n2.left) + q2.append(n2.right) + return True diff --git a/leetcode-problems/0104_maximum_depth_of_binary_tree.py b/leetcode-problems/0104_maximum_depth_of_binary_tree.py new file mode 100644 index 0000000..9c81821 --- /dev/null +++ b/leetcode-problems/0104_maximum_depth_of_binary_tree.py @@ -0,0 +1,121 @@ +""" +N: # nodes +Approach 1: Recursion +- O(# nodes), worst: O(# nodes), best: O(log(#nodes)) + +Approach 2: Tail Recursion + BFS +- O(N), T: O(N) + +Approach 3: Iteration +- O(N), T: worst: O(N), best: O(log N) +""" +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def maxDepth1(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if root is None: + return 0 + else: + left_height = self.maxDepth(root.left) + right_height = self.maxDepth(root.right) + return max(left_height, right_height) + 1 + + # approach - 2 + """ + class Solution { + private: + // The queue that contains the next nodes to visit, + // along with the level/depth that each node is located. + queue> next_items; + int max_depth = 0; + + /** + * A tail recursion function to calculate the max depth + * of the binary tree. + */ + int next_maxDepth() { + + if (next_items.size() == 0) { + return max_depth; + } + + auto next_item = next_items.front(); + next_items.pop(); + + auto next_node = next_item.first; + auto next_level = next_item.second + 1; + + max_depth = max(max_depth, next_level); + + // Add the nodes to visit in the following recursive calls. + if (next_node->left != NULL) { + next_items.push(make_pair(next_node->left, next_level)); + } + if (next_node->right != NULL) { + next_items.push(make_pair(next_node->right, next_level)); + } + + // The last action should be the ONLY recursive call + // in the tail-recursion function. + return next_maxDepth(); + } + + public: + int maxDepth(TreeNode* root) { + if (root == NULL) return 0; + + // clear the previous queue. + std::queue> empty; + std::swap(next_items, empty); + max_depth = 0; + + // push the root node into the queue to kick off the next visit. + next_items.push(make_pair(root, 0)); + + return next_maxDepth(); + } + }; + """ + def maxDepth3(self, root): + """ + :type root: TreeNode + :rtype: int + """ + stack = [] + if root is not None: + stack.append((1, root)) + + depth = 0 + while stack != []: + current_depth, root = stack.pop() + if root is not None: + depth = max(depth, current_depth) + stack.append((current_depth + 1, root.left)) + stack.append((current_depth + 1, root.right)) + + return depth + + def maxDepth(self, root): + if not root: + return 0 + + queue = [root] + depth = 0 + while queue: + node = queue.pop(0) + depth += 1 + for _ in range(len(queue)): + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + return depth \ No newline at end of file diff --git a/leetcode-problems/0118_pascals_triangle.py b/leetcode-problems/0118_pascals_triangle.py new file mode 100644 index 0000000..6c3fb77 --- /dev/null +++ b/leetcode-problems/0118_pascals_triangle.py @@ -0,0 +1,20 @@ +class Solution: + def generate(self, numRows): + ans = [] + + for r in range(numRows): + row = [None for _ in range(r + 1)] + row[0], row[-1] = 1, 1 + + for idx in range(1, len(row) - 1): + row[idx] = ans[r - 1][idx - 1] + ans[r - 1][idx] + + ans.append(row) + + return ans + + +if __name__ == "__main__": + sol = Solution() + result = sol.generate(5) + print(result) diff --git a/leetcode-problems/0125_valid_palindrome.py b/leetcode-problems/0125_valid_palindrome.py new file mode 100644 index 0000000..01bb83e --- /dev/null +++ b/leetcode-problems/0125_valid_palindrome.py @@ -0,0 +1,45 @@ +""" +Approach 1: Compare with Reverse +- O(n), O(n) + +Approach 2: Two Pointers +- O(n), O(1) +""" + + +class Solution: + def isPalindrome1(self, s: str) -> bool: + + filtered_chars = filter(lambda ch: ch.isalnum(), s) + lowercase_filtered_chars = map(lambda ch: ch.lower(), filtered_chars) + + filtered_chars_list = list(lowercase_filtered_chars) + reversed_chars_list = filtered_chars_list[::-1] + + return filtered_chars_list == reversed_chars_list + + def isPalindrome2(self, s: str) -> bool: + + i, j = 0, len(s) - 1 + + while i < j: + while i < j and not s[i].isalnum(): + i += 1 + while i < j and not s[j].isalnum(): + j -= 1 + + if i < j and s[i].lower() != s[j].lower(): + return False + + i += 1 + j -= 1 + + return True + + def isPalindrome(self, s: str) -> bool: + if len(s) == 0: + return True + else: + mod_s = (''.join(e for e in s if e.isalnum())).lower() + rev_s = mod_s[::-1] + return True if mod_s == rev_s else False diff --git a/leetcode-problems/0136_single_number.py b/leetcode-problems/0136_single_number.py new file mode 100644 index 0000000..aceea45 --- /dev/null +++ b/leetcode-problems/0136_single_number.py @@ -0,0 +1,7 @@ +class Solution: + def singleNumber(self, nums: List[int]) -> int: + from collections import Counter + d = Counter(nums) + for k, v in d.items(): + if v == 1: + return k \ No newline at end of file diff --git a/leetcode-problems/0169_majority_element.py b/leetcode-problems/0169_majority_element.py new file mode 100644 index 0000000..7f8d608 --- /dev/null +++ b/leetcode-problems/0169_majority_element.py @@ -0,0 +1,14 @@ +import collections + + +class Solution: + def majorityElement(self, nums): + counts = collections.Counter(nums) + return max(counts.keys(), key=counts.get) + + +if __name__ == "__main__": + sol = Solution() + nums = [2, 2, 1, 1, 1, 2, 2] + result = sol.majorityElement(nums) + print(result) diff --git a/leetcode-problems/0200_number_of_islands.py b/leetcode-problems/0200_number_of_islands.py new file mode 100644 index 0000000..1f38a13 --- /dev/null +++ b/leetcode-problems/0200_number_of_islands.py @@ -0,0 +1,41 @@ +""" +Approach #1 DFS [Accepted] +- O(M*N), worst: O(M*N) + +Approach #2: BFS [Accepted] +- O(M*N), O(min(M, N)) + +Approach #3: Union Find (aka Disjoint Set) [Accepted] +- O(M*N), O(M*N) +""" +class Solution: + def dfs(self, mat): + if not mat: + return 0 + + R, C = len(mat), len(mat[0]) + dirs = ((0, 1), (0, -1), (1, 0), (-1, 0)) + visited = [[False] * C for _ in range(R)] + count = 0 + + def traverse(i, j): + if visited[i][j]: + return + visited[i][j] = True + + for d in dirs: + next_i, next_j = i + d[0], j + d[1] + if 0 <= next_i < R and 0 <= next_j < C: + if mat[next_i][next_j] == mat[i][j]: + traverse(next_i, next_j) + + for i in range(R): + for j in range(C): + if not visited[i][j] and mat[i][j] == '1': + count += 1 + traverse(i, j) + return count + + def numIslands(self, grid: List[List[str]]) -> int: + count = self.dfs(grid) + return count \ No newline at end of file diff --git a/leetcode-problems/0202_happy_number.py b/leetcode-problems/0202_happy_number.py new file mode 100644 index 0000000..5e78d2e --- /dev/null +++ b/leetcode-problems/0202_happy_number.py @@ -0,0 +1,84 @@ +""" +Approach 1: Detect Cycles with a HashSet +- Time: O(243⋅3+logn+loglogn+logloglogn) = O(log n) +- Space: O(log n) + +Approach 2: Floyd's Cycle-Finding Algorithm +- O(log n), O(1) + +Approach 3: Hardcoding the Only Cycle (Advanced) +- O(log n), O(1) +""" +class Solution: + def isHappy1(self, n: int) -> bool: + + def get_next(n): + total_sum = 0 + while n > 0: + n, digit = divmod(n, 10) + total_sum += digit ** 2 + return total_sum + + seen = set() + while n != 1 and n not in seen: + seen.add(n) + n = get_next(n) + + return n == 1 + + def isHappy2(self, n: int) -> bool: + def get_next(number): + total_sum = 0 + while number > 0: + number, digit = divmod(number, 10) + total_sum += digit ** 2 + return total_sum + + slow_runner = n + fast_runner = get_next(n) + while fast_runner != 1 and slow_runner != fast_runner: + slow_runner = get_next(slow_runner) + fast_runner = get_next(get_next(fast_runner)) + return fast_runner == 1 + + def isHappy3(self, n: int) -> bool: + + cycle_members = {4, 16, 37, 58, 89, 145, 42, 20} + + def get_next(number): + total_sum = 0 + while number > 0: + number, digit = divmod(number, 10) + total_sum += digit ** 2 + return total_sum + + while n != 1 and n not in cycle_members: + n = get_next(n) + + return n == 1 + + def isHappy3_2(self, n: int) -> bool: + + def get_next(number): + total_sum = 0 + while number > 0: + number, digit = divmod(number, 10) + total_sum += digit ** 2 + return total_sum + + while n != 1 and n != 4: + n = get_next(n) + + return n == 1 + + def isHappy(self, n: int) -> bool: + while n > 4 or n == 1: + # print("The number: ", n) + square_num_sum = sum([int(i) ** 2 for i in str(n)]) + n = square_num_sum + if n == 1: + return True + else: + continue + else: + return False \ No newline at end of file diff --git a/leetcode-problems/0208_implement_trie_prefix_tree.py b/leetcode-problems/0208_implement_trie_prefix_tree.py new file mode 100644 index 0000000..13baf2e --- /dev/null +++ b/leetcode-problems/0208_implement_trie_prefix_tree.py @@ -0,0 +1,46 @@ +class Trie: + def __init__(self): + """ + Initialize your data structure here. + """ + self.nodes = {} + self.is_word = False + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + curr = self + for char in word: + if char not in curr.nodes: + curr.nodes[char] = Trie() + curr = curr.nodes[char] + curr.is_word = True + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + curr = self + for char in word: + if char not in curr.nodes: + return False + curr = curr.nodes[char] + return curr.is_word + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + curr = self + for char in prefix: + if char not in curr.nodes: + return False + curr = curr.nodes[char] + return True + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/leetcode-problems/0217_contains_duplicate.py b/leetcode-problems/0217_contains_duplicate.py new file mode 100644 index 0000000..567578c --- /dev/null +++ b/leetcode-problems/0217_contains_duplicate.py @@ -0,0 +1,3 @@ +class Solution: + def containsDuplicate(self, nums: List[int]) -> bool: + return False if (len(nums) == len(set(nums))) else True \ No newline at end of file diff --git a/leetcode-problems/0226_invert_binary_tree.py b/leetcode-problems/0226_invert_binary_tree.py new file mode 100644 index 0000000..3df576b --- /dev/null +++ b/leetcode-problems/0226_invert_binary_tree.py @@ -0,0 +1,17 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def invertTree(self, root: TreeNode) -> TreeNode: + queue = collections.deque([root]) + while queue: + node = queue.popleft() + if node: + queue.append(node.left) + queue.append(node.right) + node.left, node.right = node.right, node.left + + return root \ No newline at end of file diff --git a/leetcode-problems/0230_Kth_smallest_element_in_a_BST.py b/leetcode-problems/0230_Kth_smallest_element_in_a_BST.py new file mode 100644 index 0000000..a16a103 --- /dev/null +++ b/leetcode-problems/0230_Kth_smallest_element_in_a_BST.py @@ -0,0 +1,30 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def kthSmallest(self, root: TreeNode, k: int) -> int: + def inorder(root): + return inorder(root.left) + [root.val] + inorder(root.right) if root else [] + + return inorder(root)[k - 1] + + def kthSmallest2(self, root, k): + """ + :type root: TreeNode + :type k: int + :rtype: int + """ + stack = [] + + while True: + while root: + stack.append(root) + root = root.left + root = stack.pop() + k -= 1 + if not k: + return root.val + root = root.right diff --git a/leetcode-problems/0234_palindrome_linked_list.py b/leetcode-problems/0234_palindrome_linked_list.py new file mode 100644 index 0000000..e52ba98 --- /dev/null +++ b/leetcode-problems/0234_palindrome_linked_list.py @@ -0,0 +1,89 @@ +""" +Approach 1: Copy into Array List and then Use Two Pointer Technique +- O(n), O(n) + +Approach 2: Recursive (Advanced) +- O(n), O(n) + +Approach 3: Reverse Second Half In-place +- O(n), O(1) +""" +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def isPalindrome1(self, head: ListNode) -> bool: + vals = [] + current_node = head + while current_node is not None: + vals.append(current_node.val) + current_node = current_node.next + return vals == vals[::-1] + + def isPalindrome2(self, head: ListNode) -> bool: + + self.front_pointer = head + + def recursively_check(current_node=head): + if current_node is not None: + if not recursively_check(current_node.next): + return False + if self.front_pointer.val != current_node.val: + return False + self.front_pointer = self.front_pointer.next + return True + + return recursively_check() + + def isPalindrome(self, head: ListNode) -> bool: + ans = [] + # iterate through list and store values in list + while head: + ans.append(head.val) + head = head.next + return ans == ans[::-1] + +# approach - 3 +class Solution1: + + def isPalindrome(self, head: ListNode) -> bool: + if head is None: + return True + + # Find the end of first half and reverse second half. + first_half_end = self.end_of_first_half(head) + second_half_start = self.reverse_list(first_half_end.next) + + # Check whether or not there's a palindrome. + result = True + first_position = head + second_position = second_half_start + while result and second_position is not None: + if first_position.val != second_position.val: + result = False + first_position = first_position.next + second_position = second_position.next + + # Restore the list and return the result. + first_half_end.next = self.reverse_list(second_half_start) + return result + + def end_of_first_half(self, head): + fast = head + slow = head + while fast.next is not None and fast.next.next is not None: + fast = fast.next.next + slow = slow.next + return slow + + def reverse_list(self, head): + previous = None + current = head + while current is not None: + next_node = current.next + current.next = previous + previous = current + current = next_node + return previous \ No newline at end of file diff --git a/leetcode-problems/0238_product_of_array_except_self.py b/leetcode-problems/0238_product_of_array_except_self.py new file mode 100644 index 0000000..b0eeb3b --- /dev/null +++ b/leetcode-problems/0238_product_of_array_except_self.py @@ -0,0 +1,20 @@ +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + n = len(nums) + left = [0]*n + right = [0]*n + prod = [0]*n + + left[0] = 1 + right[n-1] = 1 + + for i in range(1, n): + left[i] = nums[i - 1] * left[i - 1] + + for i in range(n-2, -1, -1): + right[i] = nums[i + 1] * right[i + 1] + + for i in range(n): + prod[i] = left[i] * right[i] + + return prod \ No newline at end of file diff --git a/leetcode-problems/0242_valid_anagram.py b/leetcode-problems/0242_valid_anagram.py new file mode 100644 index 0000000..a7549ac --- /dev/null +++ b/leetcode-problems/0242_valid_anagram.py @@ -0,0 +1,23 @@ +import collections + + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + if len(s) != len(t): + return False + + s1 = collections.Counter(s) + t1 = collections.Counter(t) + + for char in s1: + if t1[char] != s1[char]: + return False + return True + + +if __name__ == "__main__": + sol = Solution() + s = "anagram" + t = "nagaram" + result = sol.isAnagram(s, t) + print(result) diff --git a/leetcode-problems/0258_add_digits.py b/leetcode-problems/0258_add_digits.py new file mode 100644 index 0000000..9102e9f --- /dev/null +++ b/leetcode-problems/0258_add_digits.py @@ -0,0 +1,10 @@ +class Solution: + def addDigits(self, num: int) -> int: + if num == 0: return 0 + return 1 + (num - 1) % 9 + + +if __name__ == "__main__": + sol = Solution() + result = sol.addDigits(38) + print(result) diff --git a/leetcode-problems/0278_first_bad_version.py b/leetcode-problems/0278_first_bad_version.py new file mode 100644 index 0000000..6335751 --- /dev/null +++ b/leetcode-problems/0278_first_bad_version.py @@ -0,0 +1,22 @@ +# The isBadVersion API is already defined for you. +# @param version, an integer +# @return a bool +# def isBadVersion(version): + +class Solution: + def firstBadVersion(self, n): + """ + :type n: int + :rtype: int + """ + l, r = 1, n + while l <= r: + mid = l + (r - l) // 2 + if isBadVersion(mid): + r = mid - 1 + else: + l = mid + 1 + + # print("mid: {} l: {} r: {}".format(mid, l, r)) + + return l \ No newline at end of file diff --git a/leetcode-problems/0283_move_zeroes.py b/leetcode-problems/0283_move_zeroes.py new file mode 100644 index 0000000..f52bbbf --- /dev/null +++ b/leetcode-problems/0283_move_zeroes.py @@ -0,0 +1,17 @@ +class Solution: + def moveZeroes(self, nums): + """ + Do not return anything, modify nums in-place instead. + """ + cnt = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[i], nums[cnt] = nums[cnt], nums[i] + cnt += 1 + + +if __name__ == "__main__": + sol = Solution() + num = [0, 1, 0, 3, 12] + result = sol.moveZeroes(num) + print(result) diff --git a/leetcode-problems/0328_odd_even_linked_list.py b/leetcode-problems/0328_odd_even_linked_list.py new file mode 100644 index 0000000..f07ef22 --- /dev/null +++ b/leetcode-problems/0328_odd_even_linked_list.py @@ -0,0 +1,26 @@ +""" +O(n), O(1) +""" + + +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def oddEvenList(self, head: ListNode) -> ListNode: + if not head: + return head + + odd = head + even = head.next + even_head = even + while even and even.next: + odd.next = even.next + odd = odd.next + even.next = odd.next + even = even.next + + odd.next = even_head + return head diff --git a/leetcode-problems/0344_reverse_string.py b/leetcode-problems/0344_reverse_string.py new file mode 100644 index 0000000..b284af6 --- /dev/null +++ b/leetcode-problems/0344_reverse_string.py @@ -0,0 +1,19 @@ +class Solution: + def reverseString(self, s): + """ + Do not return anything, modify s in-place instead. + """ + i, j = 0, len(s) - 1 + while i <= j: + s[i], s[j] = s[j], s[i] + i += 1 + j -= 1 + + return s + + +if __name__ == "__main__": + sol = Solution() + s = ["H", "a", "n", "n", "a", "h"] + result = sol.reverseString(s) + print(result) diff --git a/leetcode-problems/0347_top_k_frequent_elements.py b/leetcode-problems/0347_top_k_frequent_elements.py new file mode 100644 index 0000000..b0a74d2 --- /dev/null +++ b/leetcode-problems/0347_top_k_frequent_elements.py @@ -0,0 +1,16 @@ +import collections + + +class Solution: + def topKFrequent(self, nums, k): + l = list(collections.Counter(nums).items()) + l_sorted = [i for i, _ in sorted(l, key=lambda x: x[1], reverse=True)] + return l_sorted[:k] + + +if __name__ == "__main__": + sol = Solution() + nums = [1, 1, 1, 2, 2, 3] + k = 2 + result = sol.topKFrequent(nums, k) + print(result) diff --git a/leetcode-problems/0349_intersection_of_two_arrays.py b/leetcode-problems/0349_intersection_of_two_arrays.py new file mode 100644 index 0000000..33360dc --- /dev/null +++ b/leetcode-problems/0349_intersection_of_two_arrays.py @@ -0,0 +1,11 @@ +class Solution: + def intersection(self, nums1, nums2): + return list(set(nums1) & set(nums2)) + + +if __name__ == "__main__": + sol = Solution() + nums1 = [1, 2, 2, 1] + nums2 = [2, 2] + result = sol.intersection(nums1, nums2) + print(result) diff --git a/leetcode-problems/0350_intersection_of_two_arrays_II.py b/leetcode-problems/0350_intersection_of_two_arrays_II.py new file mode 100644 index 0000000..bc2f3e0 --- /dev/null +++ b/leetcode-problems/0350_intersection_of_two_arrays_II.py @@ -0,0 +1,33 @@ +""" +Approach 1: Hash Map +- O(m + n), O(min(m, n)) + +Approach 2: Sort +- O(n log(n) + m log(m)), O(1) + +""" +class Solution: + def intersect(self, nums1, nums2): + intersection_list = [] + if len(nums1) >= len(nums2): + for n in nums2: + if n in nums1: + index = nums1.index(n) + nums1.pop(index) + intersection_list.append(n) + + else: + for n in nums1: + if n in nums2: + index = nums2.index(n) + nums2.pop(index) + intersection_list.append(n) + return intersection_list + + +if __name__ == "__main__": + sol = Solution() + nums1 = [1, 2, 2, 1] + nums2 = [2, 2] + result = sol.intersect(nums1, nums2) + print(result) diff --git a/leetcode-problems/0367_valid_perfect_square.py b/leetcode-problems/0367_valid_perfect_square.py new file mode 100644 index 0000000..8bf6fb2 --- /dev/null +++ b/leetcode-problems/0367_valid_perfect_square.py @@ -0,0 +1,57 @@ +""" +Square root related problems usually could be solved in logarithmic time. +There are three standard logarithmic time approaches, listed here from the worst to the best: +Recursion. The slowest one. +Binary Search. The simplest one. +Newton's Method. The fastest one, and therefore widely used in dynamical simulations. + +Approach 1: Binary Search +- O(log N), O(1) + +Approach 2: Newton's Method +- O(log N), O(1) +""" + + +class Solution: + def isPerfectSquare1(self, num: int) -> bool: + if num < 2: + return True + + left, right = 2, num // 2 + + while left <= right: + x = left + (right - left) // 2 + guess_squared = x * x + if guess_squared == num: + return True + if guess_squared > num: + right = x - 1 + else: + left = x + 1 + + return False + + def isPerfectSquare2(self, num: int) -> bool: + if num < 2: + return True + + x = num // 2 + while x * x > num: + x = (x + num // x) // 2 + return x * x == num + + def isPerfectSquare(self, num: int) -> bool: + if num == 1: + return True + l, r = 1, num + while l <= r: + mid = (l + r) // 2 + if mid * mid == num: + return True + elif mid * mid > num: + r = mid - 1 + elif mid * mid < num: + l = mid + 1 + # print("mid: {} l: {} r: {}".format(mid, l, r)) + return False diff --git a/leetcode-problems/0383_ransom_note.py b/leetcode-problems/0383_ransom_note.py new file mode 100644 index 0000000..f85a348 --- /dev/null +++ b/leetcode-problems/0383_ransom_note.py @@ -0,0 +1,103 @@ +""" +Approach 1: Simulation +- O(m * n), O(m) + +Approach 2: Two HashMaps +- O(m), O(k=26) = O(1) + +Approach 3: One HashMap +- O(m), O(1) + +Approach 4: Sorting and Stacks +- O(m log m), O(m) +""" +import collections + + +class Solution: + def canConstruct1(self, ransomNote: str, magazine: str) -> bool: + # For each character, c, in the ransom note. + for c in ransomNote: + # If there are none of c left in the String, return False. + if c not in magazine: + return False + # Find the index of the first occurrence of c in the magazine. + location = magazine.index(c) + # Use splicing to make a new string with the characters + # before "location" (but not including), and the characters + # after "location". + magazine = magazine[:location] + magazine[location + 1:] + # If we got this far, we can successfully build the note. + return True + + def canConstruct2(self, ransomNote: str, magazine: str) -> bool: + + # Check for obvious fail case. + if len(ransomNote) > len(magazine): return False + + # In Python, we can use the Counter class. It does all the work that the + # makeCountsMap(...) function in our pseudocode did! + magazine_counts = collections.Counter(magazine) + ransom_note_counts = collections.Counter(ransomNote) + + # For each *unique* character in the ransom note: + for char, count in ransom_note_counts.items(): + # Check that the count of char in the magazine is equal + # or higher than the count in the ransom note. + magazine_count = magazine_counts[char] + if magazine_count < count: + return False + + # If we got this far, we can successfully build the note. + return True + + def canConstruct3(self, ransomNote: str, magazine: str) -> bool: + + # Check for obvious fail case. + if len(ransomNote) > len(magazine): return False + + # In Python, we can use the Counter class. It does all the work that the + # makeCountsMap(...) function in our pseudocode did! + letters = collections.Counter(magazine) + + # For each character, c, in the ransom note: + for c in ransomNote: + # If there are none of c left, return False. + if letters[c] <= 0: + return False + # Remove one of c from the Counter. + letters[c] -= 1 + # If we got this far, we can successfully build the note. + return True + + def canConstruct4(self, ransomNote: str, magazine: str) -> bool: + + # Check for obvious fail case. + if len(ransomNote) > len(magazine): return False + + # Reverse sort the note and magazine. In Python, we simply + # treat a list as a stack. + ransomNote = sorted(ransomNote, reverse=True) + magazine = sorted(magazine, reverse=True) + + # While there are letters left on both stacks: + while ransomNote and magazine: + # If the tops are the same, pop both because we have found a match. + if ransomNote[-1] == magazine[-1]: + ransomNote.pop() + magazine.pop() + # If magazine's top is earlier in the alphabet, we should remove that + # character of magazine as we definitely won't need that letter. + elif magazine[-1] < ransomNote[-1]: + magazine.pop() + # Otherwise, it's impossible for top of ransomNote to be in magazine. + else: + return False + # Return true iff the entire ransomNote was built. + return not ransomNote + + def canConstruct(self, ransomNote: str, magazine: str) -> bool: + for i in set(ransomNote): + if ransomNote.count(i) > magazine.count(i): + return False + return True \ No newline at end of file diff --git a/leetcode-problems/0387_first_unique_character_in_a_string.py b/leetcode-problems/0387_first_unique_character_in_a_string.py new file mode 100644 index 0000000..1f6a5f2 --- /dev/null +++ b/leetcode-problems/0387_first_unique_character_in_a_string.py @@ -0,0 +1,14 @@ +import collections +class Solution: + def firstUniqChar(self, s: str) -> int: + d = collections.Counter(s) + for idx, char in enumerate(s): + if d[char] == 1: + return idx + return -1 + +if __name__ == "__main__": + sol = Solution() + s = 'leetcode' + result = sol.firstUniqChar(s) + print(result) diff --git a/leetcode-problems/0402_remove_k_digits.py b/leetcode-problems/0402_remove_k_digits.py new file mode 100644 index 0000000..06f2bcf --- /dev/null +++ b/leetcode-problems/0402_remove_k_digits.py @@ -0,0 +1,87 @@ +""" +Approach 1: Brute-force [Time Limit Exceeded] + +Approach 2: Greedy with Stack +- O(n), O(n) + +Use Monotonic stack method: +- if newer element is less than stack.top, then remove the top element and append the new element. +""" +import re + +class Solution: + def removeKdigits(self, num: str, k: int) -> str: + stack = [] + # Construct a monotone increasing sequence of digits + for n in num: + while k and stack and stack[-1] > n: + stack.pop() + k -= 1 + stack.append(n) + + # - Trunk the remaining K digits at the end + # - in the case k==0: return the entire list + stack = stack[:-k] if k else stack + + # trip the leading zeros + return "".join(stack).lstrip('0') or "0" + + def removeKdigits2(self, num: str, k: int) -> str: + # if len(num) == k: + # return "0" + + stack = [] + for n in num: + while k and stack and n < stack[-1]: + stack.pop() + k -= 1 + stack.append(n) + + ans = ''.join(stack[:-k or None]).lstrip('0') or '0' + return ans + + def removeKdigits3(self, num: str, k: int) -> str: + stack = [] + for n in num: + while k and stack and n < stack[-1]: + stack.pop() + k -= 1 + stack.append(n) + + # For case like 453219 or 111111. + while k: + stack.pop() + k -= 1 + + return ''.join(stack).lstrip('0') or '0' + + def removeKdigits4(self, num, k): + sub = re.compile('1[0]|2[01]|3[0-2]|4[0-3]|5[0-4]|6[0-5]|7[0-6]|8[0-7]|9[0-8]|.$').sub + for _ in range(k): + num = sub(lambda m: m.group()[1:], num, 1) + return num.lstrip('0') or '0' + + def removeKdigits5(self, num: str, k: int) -> str: + if k == 0: + return num + while k > 0: + k -= 1 + i = 0 + while i < len(num) - 1: + if num[i] > num[i + 1]: # need to remove this ith index + break + i += 1 + num = num[:i] + num[i + 1:] + if len(num) == 0: + return "0" + return str(int(num)) + + +if __name__ == "__main__": + # num = "1432219" + num = "100" + k = 1 + # k = 3 + sol = Solution() + result = sol.removeKdigits2(num, k) + print(result) \ No newline at end of file diff --git a/leetcode-problems/0438_find_all_anagrams_in_a_string.py b/leetcode-problems/0438_find_all_anagrams_in_a_string.py new file mode 100644 index 0000000..bbc6c78 --- /dev/null +++ b/leetcode-problems/0438_find_all_anagrams_in_a_string.py @@ -0,0 +1,70 @@ +import collections + +""" +My Approach (also approach-1): +- dictionary keeping the count of the subarray of len(p). +- if the count of substring(s) == count of p, then append the index. +- O(Ns + Np), O(1) (as max 26 characters) + +Approach 2: Sliding Window with Array +- use array of size 26 to store frequency +- O(Ns + Np), O(1) (as max 26 characters) +""" + +class Solution: + def findAnagrams1(self, s: str, p: str) -> List[int]: + ns, np = len(s), len(p) + if ns < np: + return [] + + # init s_window with first len(p) elements. + p_cnt, s_window = collections.Counter(p), collections.Counter(s[0:np]) + ans = [] + + # check for first substring of s. If same, then add 0th index. + if s_window == p_cnt: + ans.append(0) + + for idx in range(np, ns): + """ + c1 - last element of current window --> increment count + c2 - first element of previous window --> decrement count + """ + c1, c2 = s[idx], s[idx - np] + s_window[c1] = s_window.setdefault(c1, 0) + 1 + + if s_window[c2] > 1: + s_window[c2] = s_window.setdefault(c2, 0) - 1 + else: + del s_window[c2] + + if s_window == p_cnt: + ans.append(idx - np + 1) + return ans + + def findAnagrams2(self, s: str, p: str) -> List[int]: + ns, np = len(s), len(p) + if ns < np: + return [] + + p_count, s_count = [0] * 26, [0] * 26 + # build reference array using string p + for ch in p: + p_count[ord(ch) - ord('a')] += 1 + + output = [] + # sliding window on the string s + for i in range(ns): + # add one more letter + # on the right side of the window + s_count[ord(s[i]) - ord('a')] += 1 + # remove one letter + # from the left side of the window + if i >= np: + s_count[ord(s[i - np]) - ord('a')] -= 1 + # compare array in the sliding window + # with the reference array + if p_count == s_count: + output.append(i - np + 1) + + return output \ No newline at end of file diff --git a/leetcode-problems/0451_sort_characters_by_frequency.py b/leetcode-problems/0451_sort_characters_by_frequency.py new file mode 100644 index 0000000..df1c01b --- /dev/null +++ b/leetcode-problems/0451_sort_characters_by_frequency.py @@ -0,0 +1,67 @@ +""" +Approach 1: Arrays and Sorting +- O(n log n), O(n) + +Approach 2: HashMap and Sort +- O(n log n), O(n) + +Approach 3: Multiset and Bucket Sort +- +""" +import collections + + +class Solution: + def frequencySort1(self, s: str) -> str: + if not s: return s + + # Convert s to a list. + s = list(s) + + # Sort the characters in s. + s.sort() + + # Make a list of strings, one for each unique char. + all_strings = [] + cur_sb = [s[0]] + for c in s[1:]: + # If the last character on string builder is different... + if cur_sb[-1] != c: + all_strings.append("".join(cur_sb)) + cur_sb = [] + cur_sb.append(c) + all_strings.append("".join(cur_sb)) + + # Sort the strings by length from *longest* to shortest. + all_strings.sort(key=lambda string: len(string), reverse=True) + + # Convert to a single string to return. + # Converting a list of strings to a string is often done + # using this rather strange looking python idiom. + return "".join(all_strings) + + def frequencySort2(self, s: str) -> str: + ans = '' + for c, freq in collections.Counter(s).most_common(): + ans += c*freq + return ans + + def frequencySort3(self, s: str) -> str: + if not s: return s + + # Determine the frequency of each character. + counts = collections.Counter(s) + max_freq = max(counts.values()) + + # Bucket sort the characters by frequency. + buckets = [[] for _ in range(max_freq + 1)] + for c, i in counts.items(): + buckets[i].append(c) + + # Build up the string. + string_builder = [] + for i in range(len(buckets) - 1, 0, -1): + for c in buckets[i]: + string_builder.append(c * i) + + return "".join(string_builder) \ No newline at end of file diff --git a/leetcode-problems/0461_hamming_distance.py b/leetcode-problems/0461_hamming_distance.py new file mode 100644 index 0000000..e70f3dc --- /dev/null +++ b/leetcode-problems/0461_hamming_distance.py @@ -0,0 +1,37 @@ +""" +Approach 1: Built-in BitCounting Functions +- O(1), O(1) + +Approach 2: Bit Shift +- O(1), O(1) + +Approach 3: Brian Kernighan's Algorithm +- O(1), O(1) +""" +class Solution: + def hammingDistance1(self, x: int, y: int) -> int: + return bin(x ^ y).count('1') + + def hammingDistance2(self, x, y): + """ + :type x: int + :type y: int + :rtype: int + """ + xor = x ^ y + distance = 0 + while xor: + # mask out the rest bits + if xor & 1: + distance += 1 + xor = xor >> 1 + return distance + + def hammingDistance3(self, x, y): + xor = x ^ y + distance = 0 + while xor: + distance += 1 + # remove the rightmost bit of '1' + xor = xor & (xor - 1) + return distance \ No newline at end of file diff --git a/leetcode-problems/0476_number_complement.py b/leetcode-problems/0476_number_complement.py new file mode 100644 index 0000000..c744eb2 --- /dev/null +++ b/leetcode-problems/0476_number_complement.py @@ -0,0 +1,53 @@ +""" +- O(1), O(1) +Approach 1: Flip Bit by Bit + +Approach 2: Compute Bit Length and Construct 1-bits Bitmask + +Approach 3: Built-in Functions to Construct 1-bits Bitmask + +Approach 4: highestOneBit OpenJDK algorithm from Hacker's Delight + +""" +from math import log2, floor + + +class Solution: + def findComplement1(self, num): + todo, bit = num, 1 + while todo: + # flip current bit + num = num ^ bit + # prepare for the next run + bit = bit << 1 + todo = todo >> 1 + return num + + def findComplement(self, num): + # n is a length of num in binary representation + n = floor(log2(num)) + 1 + # bitmask has the same length as num and contains only ones 1...1 + bitmask = (1 << n) - 1 + # flip all bits + return bitmask ^ num + + def findComplement3(self, num): + return (1 << num.bit_length()) - 1 - num + + def findComplement4(self, num): + # bitmask has the same length as num and contains only ones 1...1 + bitmask = num + bitmask |= (bitmask >> 1) + bitmask |= (bitmask >> 2) + bitmask |= (bitmask >> 4) + bitmask |= (bitmask >> 8) + bitmask |= (bitmask >> 16) + # flip all bits + return bitmask ^ num + + def findComplement(self, num: int) -> int: + """ + ex. 5 = 101 ---> complement = 2 (010) + 101 ^ 111 = 010. Here, 111(7 in decimal) = 2**(no of digits) - 1 + """ + return num ^ (pow(2, num.bit_length()) - 1) \ No newline at end of file diff --git a/leetcode-problems/0525_contiguous_array.py b/leetcode-problems/0525_contiguous_array.py new file mode 100644 index 0000000..38c7a7e --- /dev/null +++ b/leetcode-problems/0525_contiguous_array.py @@ -0,0 +1,17 @@ +class Solution: + def findMaxLength(self, nums: List[int]) -> int: + count = 0 + max_len = 0 + table = {0: 0} + for idx, num in enumerate(nums, 1): + if num == 0: + count -= 1 + else: + count += 1 + + if count in table: + max_len = max(max_len, idx - table[count]) + else: + table[count] = idx + + return max_len \ No newline at end of file diff --git a/leetcode-problems/0540_single_element_in_a_sorted_array.py b/leetcode-problems/0540_single_element_in_a_sorted_array.py new file mode 100644 index 0000000..6bda39c --- /dev/null +++ b/leetcode-problems/0540_single_element_in_a_sorted_array.py @@ -0,0 +1,78 @@ +""" +Approach 1: Brute Force +- O(n), O(1) + +Approach 2: Binary Search +- O(log n), O(1) + +Approach 3: Binary Search on Evens Indexes Only +- O(log n), O(1) +""" +class Solution: + def singleNonDuplicate1(self, nums: List[int]) -> int: + for i in range(0, len(nums) - 2, 2): + if nums[i] != nums[i + 1]: + return nums[i] + return nums[-1] + + def singleNonDuplicate2(self, nums: List[int]) -> int: + lo = 0 + hi = len(nums) - 1 + while lo < hi: + mid = lo + (hi - lo) // 2 + halves_are_even = (hi - mid) % 2 == 0 + if nums[mid + 1] == nums[mid]: + if halves_are_even: + lo = mid + 2 + else: + hi = mid - 1 + elif nums[mid - 1] == nums[mid]: + if halves_are_even: + hi = mid - 2 + else: + lo = mid + 1 + else: + return nums[mid] + return nums[lo] + + def singleNonDuplicate3(self, nums: List[int]) -> int: + lo = 0 + hi = len(nums) - 1 + while lo < hi: + mid = lo + (hi - lo) // 2 + if mid % 2 == 1: + mid -= 1 + if nums[mid] == nums[mid + 1]: + lo = mid + 2 + else: + hi = mid + return nums[lo] + + # O(n log(n)) + def singleNonDuplicate(self, nums): + if len(nums) == 1: + return nums[0] + elif len(nums) == 2: + return nums[0] ^ nums[1] + + return self.singleNonDuplicate(nums[0:len(nums) // 2]) ^ self.singleNonDuplicate(nums[len(nums) // 2:]) + + # odd ^ 1 = odd - 1 + # even ^ 1 = even + 1 + def singleNonDuplicate_1(self, nums): + lo, hi = 0, len(nums) - 1 + while lo < hi: + mid = (lo + hi) / 2 + if nums[mid] == nums[mid ^ 1]: + lo = mid + 1 + else: + hi = mid + return nums[lo] + + +if __name__ == '__main__': + soln = Solution() + # nums = [1, 1, 2, 3, 3, 4, 4, 8, 8] + nums = [3, 3, 7, 7, 10, 11, 11] + ans = soln.singleNonDuplicate(nums) + print(ans) diff --git a/leetcode-problems/0567_permutation_in_string.py b/leetcode-problems/0567_permutation_in_string.py new file mode 100644 index 0000000..e45fe1a --- /dev/null +++ b/leetcode-problems/0567_permutation_in_string.py @@ -0,0 +1,26 @@ +class Solution: + def checkInclusion(self, s1: str, s2: str) -> bool: + ns1, ns2 = len(s1), len(s2) + s1_cnt, s2_window = collections.Counter(s1), collections.Counter(s2[0:ns1]) + + # check for first substring of s2. If same, then return True + if s2_window == s1_cnt: + return True + + for idx in range(ns1, ns2): + """ + c1 - last element of current window --> increment count + c2 - first element of previous window --> decrement count + """ + c1, c2 = s2[idx], s2[idx - ns1] + # setdefault -> if key is not present in dictionary then assign 0 as default value + s2_window[c1] = s2_window.setdefault(c1, 0) + 1 + if s2_window[c2] > 1: + s2_window[c2] = s2_window.setdefault(c2, 0) - 1 + else: + del s2_window[c2] + + if s2_window == s1_cnt: + return True + return False + diff --git a/leetcode-problems/0617_merge_two_binary_trees.py b/leetcode-problems/0617_merge_two_binary_trees.py new file mode 100644 index 0000000..47a0e31 --- /dev/null +++ b/leetcode-problems/0617_merge_two_binary_trees.py @@ -0,0 +1,31 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def mergeTrees(self, t1: TreeNode, t2: TreeNode) -> TreeNode: + if not t1: + return t2 + if not t2: + return t1 + + q1, q2 = collections.deque([t1]), collections.deque([t2]) + + while q1 and q2: + n1, n2 = q1.popleft(), q2.popleft() + if n1 and n2: + n1.val += n2.val + + if not n1.left and n2.left: + n1.left = TreeNode(0) + if not n1.right and n2.right: + n1.right = TreeNode(0) + + q1.append(n1.left) + q1.append(n1.right) + q2.append(n2.left) + q2.append(n2.right) + + return t1 diff --git a/leetcode-problems/0643_maximum_average_subarray_I.py b/leetcode-problems/0643_maximum_average_subarray_I.py new file mode 100644 index 0000000..5b68cf6 --- /dev/null +++ b/leetcode-problems/0643_maximum_average_subarray_I.py @@ -0,0 +1,28 @@ +""" +Pattern: Sliding Window +Approach 1: Brute Force: O(N * k) Time Limit Exceed + +Approach 2: update window sum. +- O(n), O(1) +""" +class Solution: + def findMaxAverage(self, nums: List[int], k: int) -> float: + _sum = sum(nums[0:k]) + max_sum = _sum + + for i in range(len(nums) - k): + _sum += nums[i + k] - nums[i] + max_sum = max(max_sum, _sum) + + return max_sum / k + + def findMaxAverage1(self, nums: List[int], k: int) -> float: + _sum = sum(nums[0:k]) + max_sum = _sum + + for i in range(k, len(nums)): + _sum += nums[i] - nums[i - k] + max_sum = max(max_sum, _sum) + + max_avg = max_sum / k + return max_avg \ No newline at end of file diff --git a/leetcode-problems/0733_flood_fill.py b/leetcode-problems/0733_flood_fill.py new file mode 100644 index 0000000..2e3850d --- /dev/null +++ b/leetcode-problems/0733_flood_fill.py @@ -0,0 +1,107 @@ +import collections +""" +key thing to notice: +- need to traverse whole matrix and paint connected cells +- can use DFS/BFS (recursion, iteration) [in 4 ways] + +T: O(# pixels) | S: O(# pixels) + +Note: +visited = [[False] * C for _ in range(R)] +* We generally use "visited" variable to keep track of the nodes which have been visited. +* But, not required in this problem as we already know that we want to traverse the nodes which have old color. +""" + + +class Solution: + # BFS --> using dirs() + def floodFill(self, image, sr, sc, newColor): + R, C = len(image), len(image[0]) + color = image[sr][sc] + # vertical and horizontal directions. Can't traverse diagonally, hence can't have (1, 1) or (-1, -1) + dirs = ((0, 1), (1, 0), (-1, 0), (0, -1)) + + if color != newColor: + q = collections.deque([(sr, sc)]) + while q: + r, c = q.popleft() + image[r][c] = newColor + + for dr, dc in dirs: + cr, cc = r + dr, c + dc + # General Case: 0 <= cr < R and 0 <= cc < C and not visited[cr][cc] + if 0 <= cr < R and 0 <= cc < C and image[cr][cc] == color: + # stack --> q.appendleft() || queue --> q.append() + q.appendleft((cr, cc)) + return image + + def floodFill2(self, image, sr, sc, newColor): + R, C = len(image), len(image[0]) + color = image[sr][sc] + if color != newColor: + q = collections.deque([(sr, sc)]) + while q: + r, c = q.popleft() + # if inside boundary and color is old + if 0 <= r < R and 0 <= c < C and image[r][c] == color: + image[r][c] = newColor + q.append((r+1, c)) + q.append((r-1, c)) + q.append((r, c+1)) + q.append((r, c-1)) + + return image + """ + Recursion: two variants: + 1) Check for all corner/base cases and return if conditions are not met. + 2) Check before each recursion call. + """ + def floodFill3(self, image, sr, sc, newColor): + R, C = len(image), len(image[0]) + color = image[sr][sc] + if color == newColor: + return image + + def dfs(r, c): + # check for corner points + if not (0 <= r < R and 0 <= c < C): + return + if image[r][c] == newColor or image[r][c] != color: + return + + image[r][c] = newColor + # these four recursion call can be in any order. Doesn't matter. + dfs(r, c-1) + dfs(r, c+1) + dfs(r+1, c) + dfs(r-1, c) + + # start dfs with starting point + dfs(sr, sc) + return image + + def floodFill4(self, image, sr, sc, newColor): + R, C = len(image), len(image[0]) + color = image[sr][sc] + if color == newColor: + return image + + def dfs(r, c): + if image[r][c] == color: + image[r][c] = newColor + + if c+1 <= C-1: dfs(r, c+1) + if r+1 <= R-1: dfs(r+1, c) + if c-1 >= 0: dfs(r, c-1) + if r-1 >= 0: dfs(r-1, c) + + dfs(sr, sc) + return image + +soln = Solution() +image = [[1,1,1],[1,1,0],[1,0,1]] +sr, sc = 1, 1 +newColor = 2 +ans = soln.floodFill(image, sr, sc, newColor) +# [[2, 2, 2], [2, 2, 0], [2, 0, 1]] +print(ans) diff --git a/leetcode-problems/0746_min_cost_climbing_stairs.py b/leetcode-problems/0746_min_cost_climbing_stairs.py new file mode 100644 index 0000000..72833b0 --- /dev/null +++ b/leetcode-problems/0746_min_cost_climbing_stairs.py @@ -0,0 +1,13 @@ +class Solution: + def minCostClimbingStairs(self, cost: List[int]) -> int: + n = len(cost) + dp = [-1] * (n + 1) + dp[0], dp[1] = cost[0], cost[1] + + for i in range(2, n + 1): + if i == n: + dp[i] = min(dp[i - 1], dp[i - 2]) + else: + dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i] + + return dp[n] diff --git a/leetcode-problems/0771_jewels_and_stones.py b/leetcode-problems/0771_jewels_and_stones.py new file mode 100644 index 0000000..e02e9d4 --- /dev/null +++ b/leetcode-problems/0771_jewels_and_stones.py @@ -0,0 +1,25 @@ +""" +Approach #1: Brute Force [Accepted] +- O(J.length∗S.length)), O(1) + +Approach #2: Hash Set [Accepted] +- O(J.length∗S.length)), O(J.length) +""" +import collections + + +class Solution: + def numJewelsInStones1(self, J, S): + return sum(s in J for s in S) + + def numJewelsInStones2(self, J, S): + Jset = set(J) + return sum(s in Jset for s in S) + + def numJewelsInStones(self, J: str, S: str) -> int: + d = collections.Counter(S) + cnt = 0 + for char in J: + if char in S: + cnt += d[char] + return cnt \ No newline at end of file diff --git a/leetcode-problems/0876_middle_of_the_linked_list.py b/leetcode-problems/0876_middle_of_the_linked_list.py new file mode 100644 index 0000000..435c58c --- /dev/null +++ b/leetcode-problems/0876_middle_of_the_linked_list.py @@ -0,0 +1,12 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def middleNode(self, head: ListNode) -> ListNode: + slow = fast = head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + return slow \ No newline at end of file diff --git a/leetcode-problems/0901_online_stock_span.py b/leetcode-problems/0901_online_stock_span.py new file mode 100644 index 0000000..cb6f413 --- /dev/null +++ b/leetcode-problems/0901_online_stock_span.py @@ -0,0 +1,21 @@ +""" +T: O(Q). Q = no of calls to StockSpanner.next +S: O(Q) +""" + + +class StockSpanner: + + def __init__(self): + self.stack = [] + + def next(self, price: int) -> int: + weight = 1 + while self.stack and self.stack[-1][0] <= price: + weight += self.stack.pop()[1] + self.stack.append((price, weight)) + return weight + +# Your StockSpanner object will be instantiated and called as such: +# obj = StockSpanner() +# param_1 = obj.next(price) diff --git a/leetcode-problems/0918_maximum_sum_circular_subarray.py b/leetcode-problems/0918_maximum_sum_circular_subarray.py new file mode 100644 index 0000000..c67e547 --- /dev/null +++ b/leetcode-problems/0918_maximum_sum_circular_subarray.py @@ -0,0 +1,15 @@ +class Solution: + def maxSubarraySumCircular(self, A: List[int]) -> int: + curr_min, curr_max = 0, 0 + min_sum, max_sum = float('inf'), -float('inf') + total_sum = 0 + + for item in A: + curr_min = min(curr_min + item, item) + curr_max = max(curr_max + item, item) + + min_sum = min(min_sum, curr_min) + max_sum = max(max_sum, curr_max) + total_sum += item + + return max(max_sum, total_sum - min_sum) if max_sum > 0 else max_sum \ No newline at end of file diff --git a/leetcode-problems/0950_reveal_cards_in_increasing_order.py b/leetcode-problems/0950_reveal_cards_in_increasing_order.py new file mode 100644 index 0000000..7469663 --- /dev/null +++ b/leetcode-problems/0950_reveal_cards_in_increasing_order.py @@ -0,0 +1,14 @@ +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + N = len(deck) + index = collections.deque(range(N)) + ans = [None] * N + # print("N: {}\n index: {}\n ans: {}".format(N, index, ans)) + + for card in sorted(deck): + ans[index.popleft()] = card + if index: + index.append(index.popleft()) + # print("ans: {}\n index: {}".format(ans, index)) + + return ans \ No newline at end of file diff --git a/leetcode-problems/0986_interval_list_intersections.py b/leetcode-problems/0986_interval_list_intersections.py new file mode 100644 index 0000000..4dc1ad0 --- /dev/null +++ b/leetcode-problems/0986_interval_list_intersections.py @@ -0,0 +1,16 @@ +class Solution: + def intervalIntersection(self, A, B): + ans = [] + i = j = 0 + while i < len(A) and j < len(B): + lo, hi = max(A[i][0], B[j][0]), min(A[i][1], B[j][1]) + if lo <= hi: + ans.append([lo, hi]) + + # Remove the interval with the smallest endpoint + if A[i][1] < B[j][1]: + i += 1 + else: + j += 1 + + return ans diff --git a/leetcode-problems/0993_cousins_in_binary_tree.py b/leetcode-problems/0993_cousins_in_binary_tree.py new file mode 100644 index 0000000..b3b6a10 --- /dev/null +++ b/leetcode-problems/0993_cousins_in_binary_tree.py @@ -0,0 +1,120 @@ +""" +Approach 1: Depth First Search with Branch Pruning +- O(n), O(n) + +Approach 2: Breadth First Search with Early Stopping +- O(n), O(n) +""" +import collections + + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution1: + def __init__(self): + # To save the depth of the first node. + self.recorded_depth = None + self.is_cousin = False + + def dfs(self, node, depth, x, y): + if node is None: + return False + + # Don't go beyond the depth restricted by the first node found. + if self.recorded_depth and depth > self.recorded_depth: + return False + + if node.val == x or node.val == y: + if self.recorded_depth is None: + # Save depth for the first node. + self.recorded_depth = depth + # Return true, if the second node is found at the same depth. + return self.recorded_depth == depth + + left = self.dfs(node.left, depth + 1, x, y) + right = self.dfs(node.right, depth + 1, x, y) + + # self.recorded_depth != depth + 1 would ensure node x and y are not + # immediate child nodes, otherwise they would become siblings. + if left and right and self.recorded_depth != depth + 1: + self.is_cousin = True + + return left or right + + def isCousins(self, root: TreeNode, x: int, y: int) -> bool: + + # Recurse the tree to find x and y + self.dfs(root, 0, x, y) + return self.is_cousin + + +from collections import defaultdict + + +class Solution2: + + def isCousins(self, root: TreeNode, x: int, y: int) -> bool: + + # Queue for BFS + queue = collections.deque([root]) + + while queue: + + siblings = False + cousins = False + nodes_at_depth = len(queue) + for _ in range(nodes_at_depth): + + # FIFO + node = queue.popleft() + + # Encountered the marker. + # Siblings should be set to false as we are crossing the boundary. + if node is None: + siblings = False + else: + if node.val == x or node.val == y: + # Set both the siblings and cousins flag to true + # for a potential first sibling/cousin found. + if not cousins: + siblings, cousins = True, True + else: + # If the siblings flag is still true this means we are still + # within the siblings boundary and hence the nodes are not cousins. + return not siblings + + queue.append(node.left) if node.left else None + queue.append(node.right) if node.right else None + # Adding the null marker for the siblings + queue.append(None) + # After the end of a level if `cousins` is set to true + # This means we found only one node at this level + if cousins: + return False + + return False + + +class Solution: + def isCousins(self, root: TreeNode, x: int, y: int) -> bool: + node_data = collections.defaultdict(list) + # tuple: (node, parent, depth) + queue = collections.deque([(root, None, 0)]) + while queue: + if len(node_data) > 2: + break + + node, parent, depth = queue.popleft() + if node.val == x or node.val == y: + node_data[node.val] = [parent, depth] + if node.left: + queue.append((node.left, node.val, depth + 1)) + if node.right: + queue.append((node.right, node.val, depth + 1)) + + return node_data[x][0] != node_data[y][0] and node_data[x][1] == node_data[y][1] diff --git a/leetcode-problems/0997_find_the_town_judge.py b/leetcode-problems/0997_find_the_town_judge.py new file mode 100644 index 0000000..3335c1a --- /dev/null +++ b/leetcode-problems/0997_find_the_town_judge.py @@ -0,0 +1,51 @@ +""" +Approach 1: Two Arrays +- O(edges), O(n) + +Approach 2: One Array +- O(edges), O(n) +""" +class Solution: + def findJudge1(self, N: int, trust: List[List[int]]) -> int: + + if len(trust) < N - 1: + return -1 + + indegree = [0] * (N + 1) + outdegree = [0] * (N + 1) + + for a, b in trust: + outdegree[a] += 1 + indegree[b] += 1 + + for i in range(1, N + 1): + if indegree[i] == N - 1 and outdegree[i] == 0: + return i + return -1 + + def findJudge2(self, N: int, trust: List[List[int]]) -> int: + + if len(trust) < N - 1: + return -1 + + trust_scores = [0] * (N + 1) + + for a, b in trust: + trust_scores[a] -= 1 + trust_scores[b] += 1 + + for i, score in enumerate(trust_scores[1:], 1): + if score == N - 1: + return i + return -1 + + def findJudge(self, N: int, trust: List[List[int]]) -> int: + votes = [-1] + [0] * N + for a, b in trust: + # a loses his chance of being the judge + votes[a] = float('-inf') + votes[b] += 1 + for i, v in enumerate(votes): + # check if there is anyone got all other people's votes. + if v == N-1: return i + return -1 \ No newline at end of file diff --git a/leetcode-problems/1008_construct_binary_search_tree_from_preorder_traversal.py b/leetcode-problems/1008_construct_binary_search_tree_from_preorder_traversal.py new file mode 100644 index 0000000..2883d6d --- /dev/null +++ b/leetcode-problems/1008_construct_binary_search_tree_from_preorder_traversal.py @@ -0,0 +1,19 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def bstFromPreorder(self, preorder: List[int]) -> TreeNode: + if not preorder: + return None + + root = TreeNode(preorder[0]) + i = 1 + while i < len(preorder) and preorder[i] < root.val: + i += 1 + + root.left = self.bstFromPreorder(preorder[1:i]) + root.right = self.bstFromPreorder(preorder[i:]) + return root \ No newline at end of file diff --git a/leetcode-problems/1009_complement_of_base_10_integer.py b/leetcode-problems/1009_complement_of_base_10_integer.py new file mode 100644 index 0000000..5ea2821 --- /dev/null +++ b/leetcode-problems/1009_complement_of_base_10_integer.py @@ -0,0 +1,55 @@ +""" +- O(1), O(1) +Approach 1: Flip Bit by Bit + +Approach 2: Compute Bit Length and Construct 1-bits Bitmask + +Approach 3: Built-in Functions to Construct 1-bits Bitmask + +Approach 4: highestOneBit OpenJDK algorithm from Hacker's Delight + +""" +from math import log2, floor + +class Solution: + def bitwiseComplement1(self, N: int) -> int: + if N == 0: + return 1 + todo, bit = N, 1 + while todo: + # flip current bit + N = N ^ bit + # prepare for the next run + bit = bit << 1 + todo = todo >> 1 + return N + + def bitwiseComplement2(self, N: int) -> int: + if N == 0: + return 1 + # l is a length of N in binary representation + l = floor(log2(N)) + 1 + # bitmask has the same length as N and contains only ones 1...1 + bitmask = (1 << l) - 1 + # flip all bits + return bitmask ^ N + + def bitwiseComplement3(self, N: int) -> int: + return (1 << N.bit_length()) - 1 - N if N else 1 + + def bitwiseComplement4(self, N: int) -> int: + if N == 0: + return 1 + # bitmask has the same length as N and contains only ones 1...1 + bitmask = N + bitmask |= (bitmask >> 1) + bitmask |= (bitmask >> 2) + bitmask |= (bitmask >> 4) + bitmask |= (bitmask >> 8) + bitmask |= (bitmask >> 16) + # flip all bits + return bitmask ^ N + + def bitwiseComplement(self, N: int) -> int: + if N == 0: return 1 + else:return N ^ (2 ** N.bit_length() - 1) \ No newline at end of file diff --git a/leetcode-problems/1035_uncrossed_lines.py b/leetcode-problems/1035_uncrossed_lines.py new file mode 100644 index 0000000..88c27e5 --- /dev/null +++ b/leetcode-problems/1035_uncrossed_lines.py @@ -0,0 +1,21 @@ +class Solution: + def maxUncrossedLines(self, A: List[int], B: List[int]) -> int: + dp, m, n = collections.defaultdict(int), len(A), len(B) + for i in range(m): + for j in range(n): + dp[i, j] = max(dp[i-1, j-1] + (A[i] == B[j]), dp[i-1, j], dp[i, j-1]) + print(dp) + return dp[m-1, n-1] + + def maxUncrossedLines2(self, A: List[int], B: List[int]) -> int: + len_a, len_b = len(A), len(B) + dp = [[0] * (len_b + 1) for _ in range(len_a + 1)] + + for i in range(len_a): + for j in range(len_b): + if A[i] == B[j]: + dp[i + 1][j + 1] = dp[i][j] + 1 + else: + dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]) + + return dp[len_a][len_b] \ No newline at end of file diff --git a/leetcode-problems/1232_check_if_it_is_a_straight_line.py b/leetcode-problems/1232_check_if_it_is_a_straight_line.py new file mode 100644 index 0000000..37e71ac --- /dev/null +++ b/leetcode-problems/1232_check_if_it_is_a_straight_line.py @@ -0,0 +1,21 @@ +class Solution: + def checkStraightLine(self, coordinates: List[List[int]]) -> bool: + """ + Brute Force Solution + 1. find slope between each (xi, yi) and (x_i+1, y_i+1), i from [0, n-2] + 2. if slopes is different than previously stored slope then return False. + """ + idx = 0 + while idx <= len(coordinates) - 2: + x_i, y_i = coordinates[idx] + x_i_next, y_i_next = coordinates[idx + 1] + if x_i_next == x_i: + slope = float('inf') + else: + slope = (y_i_next - y_i) / (x_i_next - x_i) + + if idx > 0 and slope != prev_slope: + return False + prev_slope = slope + idx += 1 + return True diff --git a/leetcode-problems/1277_count_square_submatrices_with_all_ones.py b/leetcode-problems/1277_count_square_submatrices_with_all_ones.py new file mode 100644 index 0000000..e8220ac --- /dev/null +++ b/leetcode-problems/1277_count_square_submatrices_with_all_ones.py @@ -0,0 +1,7 @@ +class Solution: + def countSquares(self, matrix: List[List[int]]) -> int: + for i in range(1, len(matrix)): + for j in range(1, len(matrix[0])): + matrix[i][j] = matrix[i][j] * (min(matrix[i - 1][j], matrix[i][j - 1], matrix[i - 1][j - 1]) + 1) + + return sum(map(sum, matrix)) diff --git a/leetcode-problems/1290_convert_binary_number_in_a_linked_list_to_integer.py b/leetcode-problems/1290_convert_binary_number_in_a_linked_list_to_integer.py new file mode 100644 index 0000000..b059d44 --- /dev/null +++ b/leetcode-problems/1290_convert_binary_number_in_a_linked_list_to_integer.py @@ -0,0 +1,13 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def getDecimalValue(self, head: ListNode) -> int: + num = '' + while head: + num += str(head.val) + head = head.next + + return int(num, base=2) \ No newline at end of file diff --git a/leetcode-problems/1417_reformat_the_string.py b/leetcode-problems/1417_reformat_the_string.py new file mode 100644 index 0000000..2e67c4f --- /dev/null +++ b/leetcode-problems/1417_reformat_the_string.py @@ -0,0 +1,39 @@ +class Solution: + def reformat(self, s): + if s.isalpha(): + if len(s) is 1: + return s + else: + return "" + elif s.isdigit(): + if len(s) is 1: + return s + else: + return "" + else: + digits = [] + alphs = [] + for char in s: + if char.isalpha(): + alphs.append(char) + elif char.isdigit(): + digits.append(char) + + total_alphs = len(alphs) + total_digits = len(digits) + ans = [] + cnt = 0 if total_alphs >= total_digits else 1 + + if total_alphs == total_digits or total_alphs == total_digits + 1 or total_alphs == total_digits - 1: + while total_alphs != 0 and total_digits !=0: + if cnt % 2 is 0 and alphs: + ans.append(alphs.pop(0)) + cnt += 1 + elif digits: + ans.append(digits.pop(0)) + cnt += 1 + else: + if len(alphs) == 0 and len(digits) == 0: + return "".join(ans) + else: + return "" diff --git a/leetcode-problems/1418_display_table_of_food_orders_in_a_restaurant.py b/leetcode-problems/1418_display_table_of_food_orders_in_a_restaurant.py new file mode 100644 index 0000000..1a66999 --- /dev/null +++ b/leetcode-problems/1418_display_table_of_food_orders_in_a_restaurant.py @@ -0,0 +1,35 @@ +class Solution: + def displayTable(self, orders: List[List[str]]) -> List[List[str]]: + food_list = list() + table_f_dict = {} + for order in orders: + table_no = order[1] + food_item = order[2] + if not food_item in food_list: + food_list.append(food_item) + + table_f_dict.setdefault(table_no, list()).append(food_item) + + sorted_food_list = sorted(food_list) + + ans = [] + ans.append(['Table'] + sorted_food_list) + + temp_list = [] + d_keys = list(table_f_dict.keys()) + + sorted_d_key = sorted(d_keys, key=lambda x: int(x)) + for table in sorted_d_key: + temp_list.append(table) + f_list = table_f_dict[table] + for f in sorted_food_list: + if f in f_list: + cnt_str = str(f_list.count(f)) + temp_list.append(cnt_str) + else: + temp_list.append('0') + + ans.append(temp_list) + temp_list = [] + + return ans \ No newline at end of file diff --git a/leetcode-problems/1436_destination_city.py b/leetcode-problems/1436_destination_city.py new file mode 100644 index 0000000..c7e6b42 --- /dev/null +++ b/leetcode-problems/1436_destination_city.py @@ -0,0 +1,22 @@ +""" +You are given the array paths, where paths[i] = [cityAi, cityBi] means there exists a direct path going from cityAi to cityBi. Return the destination city, that is, the city without any path outgoing to another city. +It is guaranteed that the graph of paths forms a line without any loop, therefore, there will be exactly one destination city. + +Input: paths = [["London","New York"],["New York","Lima"],["Lima","Sao Paulo"]] +Output: "Sao Paulo" +Explanation: Starting at "London" city you will reach "Sao Paulo" city which is the destination city. Your trip consist of: "London" -> "New York" -> "Lima" -> "Sao Paulo". + +""" + +class Solution: + def destCity(self, paths: List[List[str]]) -> str: + """ + paths ---> each tuple(c1, c2) + """ + c1 = [c[0] for c in paths] + c2 = [c[1] for c in paths] + + for city in c2: + if city not in c1: + return city + \ No newline at end of file diff --git a/leetcode-problems/1437_check_if_all_1s_are_at_least_length_K_places_away.py b/leetcode-problems/1437_check_if_all_1s_are_at_least_length_K_places_away.py new file mode 100644 index 0000000..9358f02 --- /dev/null +++ b/leetcode-problems/1437_check_if_all_1s_are_at_least_length_K_places_away.py @@ -0,0 +1,25 @@ +""" +Given an array nums of 0s and 1s and an integer k, return True if all 1's are at least k places away from each other, otherwise return False. + +Input: nums = [1,0,0,0,1,0,0,1], k = 2 +Output: true +Explanation: Each of the 1s are at least 2 places away from each other. + +Input: nums = [1,1,1,1,1], k = 0 +Output: true +""" + +class Solution: + def kLengthApart(self, nums: List[int], k: int) -> bool: + count_zero = 0 + + for i, n in enumerate(nums): + if n == 1: + if i != 0 and count_zero < k: + return False + count_zero = 0 + elif n == 0: + count_zero += 1 + + if i == len(nums) - 1: + return True \ No newline at end of file