diff --git a/Graphs/Hard/README.md b/Graphs/Hard/README.md new file mode 100644 index 00000000..423d671c --- /dev/null +++ b/Graphs/Hard/README.md @@ -0,0 +1,866 @@ +The quest to identify bridge edges in a graph is a captivating challenge that invites us to navigate the intricate landscape of graph algorithms. By unraveling the connections between nodes and leveraging algorithmic tools like Tarjan's Algorithm, we not only find crucial structural elements but also enhance our understanding of graph theory. As we traverse the graph landscape, we discover the power and elegance of algorithms in solving real-world problems and maintaining the integrity of interconnected networks. + +# Introduction to Graph Algorithms + +The realm of graph algorithms presents an equally captivating and practical playground for honing your algorithmic skills and exploring the intricacies of data structures. Graph algorithms unlock hidden patterns and relationships within connected networks, opening doors to diverse applications in various fields. + +Imagine a world interconnected by roads, friendships, or even neurons in a brain. These connections, represented as edges, bridge nodes (think cities, people, or neurons) in a complex web called a graph. Graph algorithms equip us with tools to navigate and analyze these intricate relationships, revealing hidden insights and solving real-world problems. Traversing a graph involves visiting nodes and following edges. But instead of linear sequences, we explore branching paths, encounter cycles, and grapple with interconnectedness. Algorithms like Depth-First Search (DFS) and Breadth-First Search (BFS) become our trusty guides + +## Bridge Edge of a Graph + +Bridging the gap between connected components in a graph lies a special set of edges – the bridges. These sentinels guard the connectivity of the graph, and their removal leads to its fragmentation. But how do we identify these crucial guardians? Here's a procedure to unveil them: + +- **Depth-First Search (DFS):** A classic explorer, DFS delves deep into the graph, marking nodes with "discovery times" – the order they're visited. When an edge leads to a node already visited with an earlier time, it's not a bridge – another path connects them. But if the edge leads to a future-time node, it's a bridge, holding the fort against disconnection! +- **Trajan's Algorithm:** This advanced knight utilizes a similar "discovery time" concept but adds a "low-link" value – the minimum discovery time reachable from a node (including itself) through back edges. If an edge's low-link surpasses its destination's discovery time, it's a bridge, standing strong against the threat of disconnection. + +With your chosen algorithm and a dash of exploration, you've identified the bridge edges, the guardians of your graph's connectivity. Now, use them to analyze network robustness, optimize communication flow, or unlock other hidden insights within the web of connections. + +## Python Code + +```python +from collections import defaultdict + +class Graph: + def __init__(self, vertices): + # Initialize a graph with the given number of vertices + self.V = vertices + # Create a defaultdict to represent an adjacency list for the graph + self.graph = defaultdict(list) + + def add_edge(self, u, v): + # Add an undirected edge between vertices u and v + self.graph[u].append(v) + self.graph[v].append(u) + + def find_bridges(self): + # List to store bridges found in the graph + bridges = [] + + def bridge_util(current, visited, parent, low, disc): + nonlocal bridges + # Mark the current node as visited + visited[current] = True + # Set discovery time and low value for the current node + disc[current] = low[current] = self.time + self.time += 1 + + for neighbor in self.graph[current]: + if not visited[neighbor]: + # Recur for the unvisited neighbor + parent[neighbor] = current + bridge_util(neighbor, visited, parent, low, disc) + + # Update low value + low[current] = min(low[current], low[neighbor]) + + # Check for a bridge + if low[neighbor] > disc[current]: + bridges.append((current, neighbor)) + elif neighbor != parent[current]: + # Update low value for the visited neighbor + low[current] = min(low[current], disc[neighbor]) + + # Initialize data structures + visited = [False] * self.V + parent = [-1] * self.V + low = [float('inf')] * self.V + disc = [float('inf')] * self.V + self.time = 0 + + # Call the bridge utility function for each unvisited vertex + for vertex in range(self.V): + if not visited[vertex]: + bridge_util(vertex, visited, parent, low, disc) + + return bridges + +# Prompt user input for the graph +num_vertices = int(input("Enter the number of vertices: ")) +g1 = Graph(num_vertices) + +num_edges = int(input("Enter the number of edges: ")) +print("Enter the edges (format: vertex1 vertex2):") +for _ in range(num_edges): + edge_input = input().split() + edge = tuple(map(int, edge_input)) + g1.add_edge(*edge) + +# Find and print bridges +print("\nBridges in the graph:") +bridges = g1.find_bridges() +for bridge in bridges: + print(bridge) +``` + +### Step-by-Step Explanation + +### 1. Importing Libraries + +```python +from collections import defaultdict +``` + +This line imports the `defaultdict` class from the `collections` module. `defaultdict` is a subclass of the built-in `dict` class and overrides one method to provide a default value for a nonexistent key. + +### 2. Class Definition: `Graph` + +```python +class Graph: + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) +``` + +- `Graph` is a class that represents an undirected graph. +- The `__init__` method initializes the graph with a given number of vertices (`vertices`). It also creates a defaultdict to store the graph, where each vertex is associated with a list of its neighbors. + +### 3. Method: `add_edge` + +```python +def add_edge(self, u, v): + # Add an undirected edge between vertices u and v + self.graph[u].append(v) + self.graph[v].append(u) +``` + +- `add_edge` is a method to add an undirected edge between two vertices `u` and `v`. It appends `v` to the list of neighbors of `u` and vice versa. + +### 4. Method: `find_bridges` + +```python +def find_bridges(self): + bridges = [] + + def bridge_util(current, visited, parent, low, disc): + nonlocal bridges + visited[current] = True + disc[current] = low[current] = self.time + self.time += 1 + + for neighbor in self.graph[current]: + if not visited[neighbor]: + # Recur for the unvisited neighbor + parent[neighbor] = current + bridge_util(neighbor, visited, parent, low, disc) + + # Update low value + low[current] = min(low[current], low[neighbor]) + + # Check for a bridge + if low[neighbor] > disc[current]: + bridges.append((current, neighbor)) + elif neighbor != parent[current]: + # Update low value for the visited neighbor + low[current] = min(low[current], disc[neighbor]) +``` + +- `find_bridges` is a method that finds all bridges in the graph using a helper function `bridge_util`. +- `bridge_util` is a nested function that performs a Depth-First Search (DFS) traversal to find bridges. It keeps track of visited vertices, discovery times (`disc`), and low values. +- Bridges are identified based on the conditions specified in the code. + +### 5. **Initialization of Data Structures:** + +```python +pythonCopy code +visited = [False] * self.V +parent = [-1] * self.V +low = [float('inf')] * self.V +disc = [float('inf')] * self.V +self.time = 0 + +``` + +- **`visited`**: List to keep track of visited vertices during DFS. +- **`parent`**: List to store the parent of each vertex in DFS traversal. +- **`low`**: List to store the low values for each vertex. +- **`disc`**: List to store the discovery time of each vertex. +- **`self.time`**: Variable to keep track of the current time in DFS traversal. + +### 6. **DFS Traversal and Bridge Finding:** + +```python +pythonCopy code +for vertex in range(self.V): + if not visited[vertex]: + bridge_util(vertex, visited, parent, low, disc) + +``` + +- Loop through all vertices in the graph. +- If a vertex is not visited, call the **`bridge_util`** function to perform DFS traversal and find bridges. + +### 7. **User Input for Graph:** + +```python +pythonCopy code +num_vertices = int(input("Enter the number of vertices: ")) +g1 = Graph(num_vertices) + +num_edges = int(input("Enter the number of edges: ")) +print("Enter the edges (format: vertex1 vertex2):") +for _ in range(num_edges): + edge_input = input().split() + edge = tuple(map(int, edge_input)) + g1.add_edge(*edge) + +``` + +- Prompt the user to enter the number of vertices. +- Create an instance of the **`Graph`** class. +- Prompt the user to enter the number of edges. +- For each edge, prompt the user to enter the vertices and add the edge to the graph. + +### 8. **Print Bridges:** + +```python +pythonCopy code +print("\nBridges in the graph:") +bridges = g1.find_bridges() +for bridge in bridges: + print(bridge) + +``` + +- Call the **`find_bridges`** method to find bridges in the graph. +- Print the bridges. + +### 9. Example Usage + +- An instance of the `Graph` class (`g1`) is created with 5 vertices. +- Edges are added to the graph. +- The `find_bridges` method is called to identify and print the bridges in the graph. + +## C++ Code + +```cpp +#include +#include +#include + +class Graph +{ + int V; // Number of vertices + std::list *adj; // Adjacency list to represent the graph + + // Utility function to find bridges using DFS traversal + void bridgeUtil(int u, std::vector &visited, std::vector &disc, + std::vector &low, int parent); + +public: + Graph(int V); // Constructor + void addEdge(int v, int w); // Add an edge to the graph + void bridge(); // Find and print all bridges +}; + +Graph::Graph(int V) +{ + this->V = V; + adj = new std::list[V]; +} + +void Graph::addEdge(int v, int w) +{ + adj[v].push_back(w); + adj[w].push_back(v); // Graph is undirected +} + +void Graph::bridgeUtil(int u, std::vector &visited, std::vector &disc, + std::vector &low, int parent) +{ + static int time = 0; // Static variable for simplicity + + // Mark the current node as visited + visited[u] = true; + + // Initialize discovery time and low value + disc[u] = low[u] = ++time; + + // Explore all neighbors of the current node + for (int v : adj[u]) + { + if (v == parent) // Skip the edge to the parent + continue; + + if (visited[v]) + { + // If v is already visited, update the low value of u + low[u] = std::min(low[u], disc[v]); + } + else + { + // Recur for the unvisited neighbor + bridgeUtil(v, visited, disc, low, u); + + // Update the low value of u + low[u] = std::min(low[u], low[v]); + + // Check for a bridge and store it + if (low[v] > disc[u]) + std::cout << "Bridge: " << u << " " << v << std::endl; + } + } +} + +void Graph::bridge() +{ + std::vector visited(V, false); + std::vector disc(V, -1); + std::vector low(V, -1); + + std::cout << "\nBridges in the graph:\n"; + + // Call the recursive helper function for each unvisited vertex + for (int i = 0; i < V; ++i) + { + if (!visited[i]) + { + bridgeUtil(i, visited, disc, low, -1); + } + } +} + +int main() +{ + int vertices, edges; + std::cout << "Enter the number of vertices: "; + std::cin >> vertices; + + std::cout << "Enter the number of edges: "; + std::cin >> edges; + + std::cout << "\nEnter the edges (format: vertex1 vertex2):\n"; + Graph g(vertices); + for (int i = 0; i < edges; ++i) + { + int v, w; + std::cin >> v >> w; + g.addEdge(v, w); + } + + g.bridge(); + + return 0; +} + +// Enter the number of vertices: 8 +// Enter the number of edges: 10 +// Enter the edges (format: vertex1 vertex2): +// 0 1 +// 1 2 +// 2 0 +// 1 3 +// 3 4 +// 4 5 +// 5 3 +// 6 7 +// 7 6 +// 5 6 +// Bridges in the graph: +// 6 7 +// 5 6 +// 1 3 +``` + +### Step-by-Step Explanation + +### 1. **Header and Namespace** + +```cpp +#include +#include +#include +``` + +These lines include the necessary C++ Standard Library headers. **``** is for input and output operations, **``** is for using linked lists, and **``** is for using dynamic arrays. + +### 2. **Class Definition: `Graph`** + +```cpp +class Graph +{ + int V; + std::list *adj; +``` + +Defines a class named `Graph` to represent an undirected graph. + +`V`: Number of vertices in the graph. + +**`std::list* adj`**: This is a pointer to an array of linked lists. Each element of the array corresponds to a vertex in the graph, and the linked lists represent the adjacency lists for each vertex. Each linked list contains the vertices adjacent to the corresponding vertex. + +### 3. **Constructor: `Graph(int V)`** + +```cpp +Graph::Graph(int V) +{ + this->V = V; + adj = new std::list[V]; +} +``` + +This initializes a graph with a given number of vertices. + +**`this`** is a pointer that points to the current instance of the class. Here, it is used to distinguish the member variable **`V`** from the parameter **`V`**. + +**`this->V = V;`** initializes the member variable **`V`** with the value passed as a parameter. + +**`adj`** is a member variable representing the adjacency list of the graph. + +**`new std::list[V];`** dynamically allocates memory for an array of linked lists, where each list corresponds to a vertex in the graph. + +Dynamic memory is allocated for the adjacency list. + +### 4. **Method: `addEdge(int v, int w)`** + +```cpp +void Graph::addEdge(int v, int w) +{ + adj[v].push_back(w); + adj[w].push_back(v); +} +``` + +Adds an undirected edge between vertices `v` and `w` to the graph. + +Adds `w` to the adjacency list of `v` and vice versa. + +**`push_back(w)`** adds vertex **`w`** to the end of the linked list, representing the fact that there is an edge from vertex **`v`** to vertex **`w`**. + +For an undirected graph, the edge is bidirectional. Therefore, after adding an edge from **`v`** to **`w`**, this line adds an edge from **`w`** to **`v`** to ensure symmetry in the adjacency list. + +### 5. **DFS-based Bridge Finding Utility Function: `bridgeUtil`** + +```cpp +void Graph::bridgeUtil(int u, std::vector &visited, std::vector &disc, std::vector &low, int parent) +{ + static int time = 0; +``` + +This implements a DFS-based utility function to find bridges in the graph. + +It declares the **`bridgeUtil`** method within the **`Graph`** class. It takes parameters for the current vertex **`u`**, the **`visited`** array to track visited vertices, **`disc`** array for discovery time, **`low`** array for low value, and **`parent`** representing the parent vertex in the DFS traversal. + +**`static int time = 0;`** declares a static variable **`time`** that is initialized to 0. It is used to keep track of the discovery time during the DFS traversal. The use of **`static`** means that the variable retains its value between function calls. + +### 6. **DFS-based Bridge Finding Utility Function (Continued)** + +```cpp + + visited[u] = true; + + disc[u] = low[u] = ++time; +``` + +This marks the current node as visited and initializes discovery time and low value. + +### 7. **DFS-based Bridge Finding Utility Function (Continued)** + +```cpp + + for (int v : adj[u]) + { + if (v == parent) + continue; + + if (visited[v]) + { + low[u] = std::min(low[u], disc[v]); + } + else + { + parent = u; + bridgeUtil(v, visited, disc, low, parent); + low[u] = std::min(low[u], low[v]); + if (low[v] > disc[u]) + std::cout << u << " " << v << endl; + } + } +} +``` + +Explores all neighbors of the current node. + +Updates low values and identifies bridges based on conditions. + +### 8. **Method: `bridge`** + +```cpp +void Graph::bridge() +{ + std::vector visited(V, false); + std::vector disc(V, -1); + std::vector low(V, -1); + + int parent = -1; + + + for (int i = 0; i < V; ++i) + { + if (!visited[i]) + { + bridgeUtil(i, visited, disc, low, -1); + } + } +} +``` + +These lines create three vectors (**`visited`**, **`disc`**, and **`low`**) to store information during the DFS traversal for finding bridges. + +**`visited`**: Marks vertices as visited. + +**`disc`**: Records the discovery time of each vertex. + +**`low`**: Keeps track of the lowest discovery time reachable from the vertex. + +### 9. **Main Function** + +- Creates an instance of `Graph` (`g1`) with some vertices. +- Adds edges to represent a sample graph. +- Calls the `bridge` method to find and print bridges. + +## Java Code + +```java +import java.util.*; + +public class bridge_edge { + private static class Graph { + private int V; // Number of vertices + private LinkedList adj[]; // Adjacency list to represent the graph + private int time = 0; + private static final int NIL = -1; + + // Constructor + @SuppressWarnings("unchecked") + Graph(int v) { + V = v; + adj = new LinkedList[v]; + for (int i = 0; i < v; ++i) + adj[i] = new LinkedList<>(); + } + + // Function to add an edge into the graph + void addEdge(int v, int w) { + adj[v].add(w); // Add w to v's list. + adj[w].add(v); // Add v to w's list + } + + // A recursive function that finds and prints bridges using DFS traversal + void bridgeUtil(int u, boolean visited[], int disc[], int low[], int parent[]) { + // Mark the current node as visited + visited[u] = true; + + // Initialize discovery time and low value + disc[u] = low[u] = ++time; + + // Go through all vertices adjacent to this + Iterator i = adj[u].iterator(); + while (i.hasNext()) { + int v = i.next(); // v is the current adjacent of u + + // If v is not visited yet, then make it a child of u in DFS tree and recur for + // it. + // If v is not visited yet, then recur for it + if (!visited[v]) { + parent[v] = u; + bridgeUtil(v, visited, disc, low, parent); + + // Check if the subtree rooted with v has a connection to one of the ancestors + // of u + low[u] = Math.min(low[u], low[v]); + + // If the lowest vertex reachable from the subtree under v is below u in DFS + // tree, then u-v is a bridge + if (low[v] > disc[u]) + System.out.println(u + " " + v); + } + + // Update the low value of u for parent function calls. + else if (v != parent[u]) + low[u] = Math.min(low[u], disc[v]); + } + } + + // DFS based function to find all bridges. It uses the recursive function + // bridgeUtil() + void bridge() { + // Mark all the vertices as not visited + boolean visited[] = new boolean[V]; + int disc[] = new int[V]; + int low[] = new int[V]; + int parent[] = new int[V]; + + // Initialize parent and visited arrays + Arrays.fill(parent, NIL); + + // Call the recursive helper function to find Bridges in DFS tree rooted with + // vertex 'i' + for (int i = 0; i < V; i++) + if (!visited[i]) + bridgeUtil(i, visited, disc, low, parent); + } + } + + public static void main(String args[]) { + Scanner scanner = new Scanner(System.in); + + System.out.print("Enter the number of vertices: "); + int vertices = scanner.nextInt(); + + Graph g = new Graph(vertices); + + System.out.print("Enter the number of edges: "); + int edges = scanner.nextInt(); + + System.out.println("Enter the edges (format: vertex1 vertex2):"); + for (int i = 0; i < edges; i++) { + int v = scanner.nextInt(); + int w = scanner.nextInt(); + g.addEdge(v, w); + } + + System.out.println("Bridges in the graph:"); + g.bridge(); + + scanner.close(); + } +} + +// Enter the number of vertices: 8 +// Enter the number of edges: 10 +// Enter the edges (format: vertex1 vertex2): +// 0 1 +// 1 2 +// 2 0 +// 1 3 +// 3 4 +// 4 5 +// 5 3 +// 6 7 +// 7 6 +// 5 6 +// Bridges in the graph: +// 6 7 +// 5 6 +// 1 3 +``` + +### Step-by-Step Explanation + +### 1. **Class Definition: `Graph`** + +```java +private static class Graph { + private int V; // Number of vertices + private LinkedList adj[]; // Adjacency list to represent the graph + private int time = 0; + private static final int NIL = -1; + + // Constructor + @SuppressWarnings("unchecked") + Graph(int v) { + V = v; + adj = new LinkedList[v]; + for (int i = 0; i < v; ++i) + adj[i] = new LinkedList<>(); + } +``` + +This defines a nested static class `Graph` to represent an undirected graph. + +### **`private static class Graph`** + +This defines a nested static class named **`Graph`**. It encapsulates the functionality of an undirected graph and contains: + +### **`private int V; // Number of vertices`** + +Represents the number of vertices in the graph. + +If **`V`** is 5, the graph has 5 vertices. + +### **`private LinkedList adj[]; // Adjacency list to represent the graph`** + +Represents the graph using an adjacency list. For each vertex, it stores a list of adjacent vertices. + +**`adj[0]`** might contain **`[1, 2, 3]`** if vertices 1, 2, and 3 are adjacent to vertex 0. + +### **`private int time = 0;`** + +Used to keep track of the discovery time during the DFS traversal. + +In DFS, **`time`** is incremented as each node is visited. + +### **`private static final int NIL = -1;`** + +A constant representing a special value indicating no parent. It's typically used to initialize parent arrays. + +**`parent[i] = NIL;`** sets the parent of vertex **`i`** to an initial invalid value. + +### **`@SuppressWarnings("unchecked")`** + +This annotation is used to suppress compiler warnings related to generic types when using arrays. In this case, it's applied to the array of linked lists. + +It prevents a warning that would otherwise be generated due to the use of raw types in the array creation. + +### **`Graph(int v) { ... }`** + +Constructor method for the **`Graph`** class. Initializes the graph with a given number of vertices. + +**`Graph g = new Graph(5);`** creates a graph with 5 vertices. + +### **`adj = new LinkedList[v];`** + +Allocates memory for the adjacency list array. Each element of the array is a linked list. + +**`adj[2] = new LinkedList<>();`** initializes an empty linked list for vertex 2. + +### **`for (int i = 0; i < v; ++i) adj[i] = new LinkedList<>();`** + +Initializes each linked list in the array, making them empty initially. + +This loop sets up an empty linked list for each vertex in the graph. + +### 2. **Method: `addEdge(int v, int w)`** + +```java +// Function to add an edge into the graph +void addEdge(int v, int w) { + adj[v].add(w); // Add w to v's list. + adj[w].add(v); // Add v to w's list +} +``` + +Adds an undirected edge between vertices `v` and `w` to the graph and also adds `w` to the adjacency list of `v` and vice versa. + +### 3. **DFS-based Bridge Finding Utility Function: `bridgeUtil`** + +```java +// A recursive function that finds and prints bridges using DFS traversal +void bridgeUtil(int u, boolean visited[], int disc[], int low[], int parent[]) { + // Mark the current node as visited + visited[u] = true; + + // Initialize discovery time and low value + disc[u] = low[u] = ++time; + + // Go through all vertices adjacent to this + Iterator i = adj[u].iterator(); + while (i.hasNext()) { + int v = i.next(); // v is the current adjacent of u + + // If v is not visited yet, then make it a child of u in DFS tree and recur for it. + // If v is not visited yet, then recur for it + if (!visited[v]) { + parent[v] = u; + bridgeUtil(v, visited, disc, low, parent); + + // Check if the subtree rooted with v has a connection to one of the ancestors + // of u + low[u] = Math.min(low[u], low[v]); + + // If the lowest vertex reachable from the subtree under v is below u in DFS tree, + // then u-v is a bridge + if (low[v] > disc[u]) + System.out.println(u + " " + v); + } + + // Update the low value of u for parent function calls. + else if (v != parent[u]) + low[u] = Math.min(low[u], disc[v]); + } +} + +``` + +- **`visited[u] = true;`**: Marks the current node as visited. +- **`disc[u] = low[u] = ++time;`**: Initializes the discovery time (`disc[u]`) and low value (`low[u]`) for the current node `u`. The `time` variable is incremented. + +### Traverse Adjacent Vertices + +- **`Iterator i = adj[u].iterator();`**: Initializes an iterator to traverse the adjacent vertices of `u` stored in the adjacency list. + +### Recursive DFS + +- **`if (!visited[v]) { ... }`**: Checks if vertex `v` is not visited. + - **`parent[v] = u;`**: Sets `u` as the parent of `v` in the DFS tree. + - **`bridgeUtil(v, visited, disc, low, parent);`**: Recursively calls `bridgeUtil` for the unvisited vertex `v`. + - **`low[u] = Math.min(low[u], low[v]);`**: Updates the low value of `u` based on the low value of `v`. + - **`if (low[v] > disc[u]) System.out.println(u + " " + v);`**: Checks if the lowest vertex reachable from the subtree rooted at `v` is below `u` in the DFS tree. If true, `u-v` is a bridge, and it's printed. + +### Update Low Value + +- **`else if (v != parent[u]) low[u] = Math.min(low[u], disc[v]);`**: Updates the low value of `u` for the parent function calls. It ensures that `low[u]` considers the low value of `v` from its children. + +### 4. **Method: `bridge`** + +```java +// DFS based function to find all bridges. It uses the recursive function bridgeUtil() +void bridge() { + // Mark all the vertices as not visited + boolean visited[] = new boolean[V]; + int disc[] = new int[V]; + int low[] = new int[V]; + int parent[] = new int[V]; + + // Initialize parent and visited arrays + Arrays.fill(parent, NIL); + + // Call the recursive helper function to find Bridges in DFS tree rooted with vertex 'i' + for (int i = 0; i < V; i++) + if (!visited[i]) + bridgeUtil(i, visited, disc, low, parent); +} + +``` + +Initiates the bridge-finding process for the entire graph. + +### 5. **Main Function** + +Creates an instance of `Graph` (`g1`) with 5 vertices. + +Adds edges to represent a sample graph. + +Calls the `bridge` method to find and print bridges. + +## Time and Space Complexity Analysis + +### **Time Complexity:** + +The time complexity of the bridge-finding algorithm is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because the algorithm uses a depth-first search (DFS) traversal, which visits each vertex and each edge once. + +In the worst case, the algorithm explores all vertices and edges in the graph. The DFS traversal takes O(V + E) time, and the additional work done to identify bridges and update the low values does not exceed this time complexity. + +### **Space Complexity:** + +The space complexity of the algorithm is O(V), where V is the number of vertices. This space is used for the data structures such as arrays to keep track of visited vertices, discovery times (**`disc`**), low values (**`low`**), and parent vertices. + +Specifically: + +- **`visited`**, **`disc`**, **`low`**, and **`parent`** arrays each use O(V) space. +- The recursion depth of the DFS traversal is at most V, contributing to the call stack space. + +The adjacency list representation of the graph is not considered in the space complexity analysis, as it is assumed to be given and not created by the algorithm. + +## Real world Applications + +The bridge-finding algorithm has various real-world applications, particularly in network analysis, transportation systems, and communication networks. Here are some examples: + +1. **Network Design and Maintenance:** + - In computer networks, identifying bridges helps optimize the design and layout of the network. Bridges are critical links, and understanding them can lead to better network design and maintenance. +2. **Transportation Systems:** + - In transportation networks, bridges can represent critical road segments or intersections. Identifying bridges helps in analyzing the robustness and efficiency of transportation systems. For instance, determining the critical road links in a city's road network can aid in traffic management and infrastructure planning. +3. **Communication Networks:** + - In communication networks, bridges may correspond to key routers or network nodes. Identifying bridges is crucial for ensuring fault tolerance and reliability in communication systems. It helps in understanding how the removal of specific nodes may impact the overall network connectivity. +4. **Social Networks:** + - In social network analysis, bridges could represent individuals whose connections are essential for maintaining connectivity within a community. Identifying bridges can help understand social structures and key influencers. +5. **Ecology and Biology:** + - In ecology, bridges might represent crucial ecological corridors that facilitate the movement of species between isolated habitats. Identifying these bridges aids in conservation efforts and understanding the impact of landscape changes on biodiversity. +6. **Electric Power Grids:** + - In power grids, bridges can represent critical transmission lines or substations. Identifying bridges is important for analyzing the vulnerability of the power grid and ensuring a reliable supply of electricity. +7. **Software Engineering:** + - In software engineering, the concept of bridges can be applied to dependencies between software components. Identifying critical dependencies helps in understanding the impact of changes in one component on the entire system. +8. **Epidemiology:** + - In epidemiology, bridges may represent individuals who are crucial for disease transmission between different populations. Identifying these bridges is essential for developing effective strategies to control the spread of diseases. + +Understanding and identifying bridge edges provide valuable insights into the structure and vulnerabilities of various complex systems, making the algorithm applicable in a wide range of fields. \ No newline at end of file diff --git a/Graphs/Hard/bridge_edge.cpp b/Graphs/Hard/bridge_edge.cpp new file mode 100644 index 00000000..361680d0 --- /dev/null +++ b/Graphs/Hard/bridge_edge.cpp @@ -0,0 +1,126 @@ +#include +#include +#include + +class Graph +{ + int V; // Number of vertices + std::list *adj; // Adjacency list to represent the graph + + // Utility function to find bridges using DFS traversal + void bridgeUtil(int u, std::vector &visited, std::vector &disc, + std::vector &low, int parent); + +public: + Graph(int V); // Constructor + void addEdge(int v, int w); // Add an edge to the graph + void bridge(); // Find and print all bridges +}; + +Graph::Graph(int V) +{ + this->V = V; + adj = new std::list[V]; +} + +void Graph::addEdge(int v, int w) +{ + adj[v].push_back(w); + adj[w].push_back(v); // Graph is undirected +} + +void Graph::bridgeUtil(int u, std::vector &visited, std::vector &disc, + std::vector &low, int parent) +{ + static int time = 0; // Static variable for simplicity + + // Mark the current node as visited + visited[u] = true; + + // Initialize discovery time and low value + disc[u] = low[u] = ++time; + + // Explore all neighbors of the current node + for (int v : adj[u]) + { + if (v == parent) // Skip the edge to the parent + continue; + + if (visited[v]) + { + // If v is already visited, update the low value of u + low[u] = std::min(low[u], disc[v]); + } + else + { + // Recur for the unvisited neighbor + bridgeUtil(v, visited, disc, low, u); + + // Update the low value of u + low[u] = std::min(low[u], low[v]); + + // Check for a bridge and store it + if (low[v] > disc[u]) + std::cout << "Bridge: " << u << " " << v << std::endl; + } + } +} + +void Graph::bridge() +{ + std::vector visited(V, false); + std::vector disc(V, -1); + std::vector low(V, -1); + + std::cout << "\nBridges in the graph:\n"; + + // Call the recursive helper function for each unvisited vertex + for (int i = 0; i < V; ++i) + { + if (!visited[i]) + { + bridgeUtil(i, visited, disc, low, -1); + } + } +} + +int main() +{ + int vertices, edges; + std::cout << "Enter the number of vertices: "; + std::cin >> vertices; + + std::cout << "Enter the number of edges: "; + std::cin >> edges; + + std::cout << "\nEnter the edges (format: vertex1 vertex2):\n"; + Graph g(vertices); + for (int i = 0; i < edges; ++i) + { + int v, w; + std::cin >> v >> w; + g.addEdge(v, w); + } + + g.bridge(); + + return 0; +} + +// Enter the number of vertices: 8 +// Enter the number of edges: 10 +// Enter the edges (format: vertex1 vertex2): +// 0 1 +// 1 2 +// 2 0 +// 1 3 +// 3 4 +// 4 5 +// 5 3 +// 6 7 +// 7 6 +// 5 6 +// Bridges in the graph: +// 6 7 +// 5 6 +// 1 3 \ No newline at end of file diff --git a/Graphs/Hard/bridge_edge.java b/Graphs/Hard/bridge_edge.java new file mode 100644 index 00000000..cd37fc51 --- /dev/null +++ b/Graphs/Hard/bridge_edge.java @@ -0,0 +1,122 @@ +import java.util.*; + +public class bridge_edge { + private static class Graph { + private int V; // Number of vertices + private LinkedList adj[]; // Adjacency list to represent the graph + private int time = 0; + private static final int NIL = -1; + + // Constructor + @SuppressWarnings("unchecked") + Graph(int v) { + V = v; + adj = new LinkedList[v]; + for (int i = 0; i < v; ++i) + adj[i] = new LinkedList<>(); + } + + // Function to add an edge into the graph + void addEdge(int v, int w) { + adj[v].add(w); // Add w to v's list. + adj[w].add(v); // Add v to w's list + } + + // A recursive function that finds and prints bridges using DFS traversal + void bridgeUtil(int u, boolean visited[], int disc[], int low[], int parent[]) { + // Mark the current node as visited + visited[u] = true; + + // Initialize discovery time and low value + disc[u] = low[u] = ++time; + + // Go through all vertices adjacent to this + Iterator i = adj[u].iterator(); + while (i.hasNext()) { + int v = i.next(); // v is the current adjacent of u + + // If v is not visited yet, then make it a child of u in DFS tree and recur for + // it. + // If v is not visited yet, then recur for it + if (!visited[v]) { + parent[v] = u; + bridgeUtil(v, visited, disc, low, parent); + + // Check if the subtree rooted with v has a connection to one of the ancestors + // of u + low[u] = Math.min(low[u], low[v]); + + // If the lowest vertex reachable from the subtree under v is below u in DFS + // tree, then u-v is a bridge + if (low[v] > disc[u]) + System.out.println(u + " " + v); + } + + // Update the low value of u for parent function calls. + else if (v != parent[u]) + low[u] = Math.min(low[u], disc[v]); + } + } + + // DFS based function to find all bridges. It uses the recursive function + // bridgeUtil() + void bridge() { + // Mark all the vertices as not visited + boolean visited[] = new boolean[V]; + int disc[] = new int[V]; + int low[] = new int[V]; + int parent[] = new int[V]; + + // Initialize parent and visited arrays + Arrays.fill(parent, NIL); + + // Call the recursive helper function to find Bridges in DFS tree rooted with + // vertex 'i' + for (int i = 0; i < V; i++) + if (!visited[i]) + bridgeUtil(i, visited, disc, low, parent); + } + } + + public static void main(String args[]) { + Scanner scanner = new Scanner(System.in); + + System.out.print("Enter the number of vertices: "); + int vertices = scanner.nextInt(); + + Graph g = new Graph(vertices); + + System.out.print("Enter the number of edges: "); + int edges = scanner.nextInt(); + + System.out.println("Enter the edges (format: vertex1 vertex2):"); + for (int i = 0; i < edges; i++) { + int v = scanner.nextInt(); + int w = scanner.nextInt(); + g.addEdge(v, w); + } + + System.out.println("Bridges in the graph:"); + g.bridge(); + + scanner.close(); + } +} + +// Enter the number of vertices: 8 +// Enter the number of edges: 10 +// Enter the edges (format: vertex1 vertex2): +// 0 1 +// 1 2 +// 2 0 +// 1 3 +// 3 4 +// 4 5 +// 5 3 +// 6 7 +// 7 6 +// 5 6 +// Bridges in the graph: +// 6 7 +// 5 6 +// 1 3 \ No newline at end of file diff --git a/Graphs/Hard/bridge_edge.py b/Graphs/Hard/bridge_edge.py new file mode 100644 index 00000000..d15113b0 --- /dev/null +++ b/Graphs/Hard/bridge_edge.py @@ -0,0 +1,90 @@ +from collections import defaultdict + +class Graph: + def __init__(self, vertices): + # Initialize a graph with the given number of vertices + self.V = vertices + # Create a defaultdict to represent an adjacency list for the graph + self.graph = defaultdict(list) + + def add_edge(self, u, v): + # Add an undirected edge between vertices u and v + self.graph[u].append(v) + self.graph[v].append(u) + + def find_bridges(self): + # List to store bridges found in the graph + bridges = [] + + def bridge_util(current, visited, parent, low, disc): + nonlocal bridges + # Mark the current node as visited + visited[current] = True + # Set discovery time and low value for the current node + disc[current] = low[current] = self.time + self.time += 1 + + for neighbor in self.graph[current]: + if not visited[neighbor]: + # Recur for the unvisited neighbor + parent[neighbor] = current + bridge_util(neighbor, visited, parent, low, disc) + + # Update low value + low[current] = min(low[current], low[neighbor]) + + # Check for a bridge + if low[neighbor] > disc[current]: + bridges.append((current, neighbor)) + elif neighbor != parent[current]: + # Update low value for the visited neighbor + low[current] = min(low[current], disc[neighbor]) + + # Initialize data structures + visited = [False] * self.V + parent = [-1] * self.V + low = [float('inf')] * self.V + disc = [float('inf')] * self.V + self.time = 0 + + # Call the bridge utility function for each unvisited vertex + for vertex in range(self.V): + if not visited[vertex]: + bridge_util(vertex, visited, parent, low, disc) + + return bridges + +# Prompt user input for the graph +num_vertices = int(input("Enter the number of vertices: ")) +g1 = Graph(num_vertices) + +num_edges = int(input("Enter the number of edges: ")) +print("Enter the edges (format: vertex1 vertex2):") +for _ in range(num_edges): + edge_input = input().split() + edge = tuple(map(int, edge_input)) + g1.add_edge(*edge) + +# Find and print bridges +print("\nBridges in the graph:") +bridges = g1.find_bridges() +for bridge in bridges: + print(bridge) + +# Enter the number of vertices: 8 +# Enter the number of edges: 10 +# Enter the edges (format: vertex1 vertex2): +# 0 1 +# 1 2 +# 2 0 +# 1 3 +# 3 4 +# 4 5 +# 5 3 +# 6 7 +# 7 6 +# 5 6 +# Bridges in the graph: +# 6 7 +# 5 6 +# 1 3 \ No newline at end of file diff --git a/Strings/Easy/robot_return_to_origin/README.md b/Strings/Easy/robot_return_to_origin/README.md new file mode 100644 index 00000000..55572013 --- /dev/null +++ b/Strings/Easy/robot_return_to_origin/README.md @@ -0,0 +1,340 @@ +# **Exploring String Algorithms : Robot return to Origin** + +Discover the realm of a particular emphasis on uncovering the robot return to origin problem through the utilization of string algorithm. This intriguing challenge not only captivates but also offers a practical avenue to delve into the intricacies of data structures and foster algorithmic thinking. + +# Introduction to String Algorithms + +String algorithms, a versatile toolkit for tackling an array of computational challenges. String algorithms, designed for the manipulation and analysis of sequences of characters, are essential in addressing a wide spectrum of problems in computer science. Within this domain, string algorithms prove instrumental in tasks such as pattern matching, substring search, and the optimization of various string-related operations. + +As we explore, we'll know much about fundamental string algorithms, examining techniques like string matching, regular expressions, and dynamic programming. Join this journey into the heart of string manipulation, where the algorithms we encounter will become indispensable tools for deciphering, analyzing, and extracting valuable information from the world of characters and text. + +One of the fundamental case in string algorithms is Robot return to Origin. + +## Robot return to Origin + +The "Robot Return to Origin" is a challenge, where a robot follows a sequence of instructions and the goal is to determine if the robot returns to its initial position. + + It involves a robot moving on a 2D plane, following a sequence of instructions represented by the characters 'U' (up), 'D' (down), 'R' (right), and 'L' (left). The task is to determine whether the robot returns to the origin (0, 0) after executing the given instructions. + + U + + | + +L — (origin) — R + + | + + D + +## Python Code + +```python +# Copyrights to venkys.io +# For more programs visit venkys.io +# Python program for robot return to origin + +def robot_return_to_origin(input): + # Initialize the coordinates to (0, 0) + x = y = 0 + + # Iterate through each character in the input string + for i in input: + # Update coordinates based on the current direction + if i == "U": #U denotes "UP" and it moves towards top from the origin(y-axis) + y += 1 + elif i == "D": #D denotes "DOWN" and it moves bottom from the origin(y-axis) + y -= 1 + elif i == "R": #R denotes "RIGHT" and it moves right hand side from the origin(x-axis) + x += 1 + elif i == "L": #L denotes "LEFT" and it moves left hand side from the origin(x-axis) + x -= 1 + else: + # Handle invalid input characters other than "R,U,L,D" + print("Wrong input") + + # Check if the final coordinates are at the origin (0, 0) + return x == 0 and y == 0 + +# Get user input for directions (case-insensitive) +z = input() +z = z.upper() # Convert input to uppercase for case-insensitivity + +# Call the function and print the result +print(robot_return_to_origin(z)) +#returns True if the robot returns to the origin else returns False +``` + +### **Step-by-Step Explanation:** + +**1. Function Definition:** + +- `def robot_return_to_origin(input):`: This line defines a function named `robot_return_to_origin` that takes a string `input` as a parameter. The function is designed to check if a robot, represented by a sequence of directional inputs, returns to the origin (0,0) on a 2D plane. + +**2. Initialize Position:** + +- `x = y = 0`: Initializes two variables `x` and `y` to zero. These variables represent the current position of the robot on the x-axis and y-axis, respectively. + +**3. Iterate Through Input:** + +- `for i in input:`: Initiates a loop that iterates through each character (`i`) in the input string. The loop updates the robot's position based on the directional inputs. + +**4. Update Position:** + +- The `if-elif-else` block inside the loop updates the robot's position based on the current character: + - `if i == "U": y += 1`: Move up (increment `y`). + - `elif i == "D": y -= 1`: Move down (decrement `y`). + - `elif i == "R": x += 1`: Move right (increment `x`). + - `elif i == "L": x -= 1`: Move left (decrement `x`). + - `else: print("wrong input")`: Prints an error message if the input contains an invalid character other than “R”,”L”,”U”,”D”. +- The `return x == 0 and y == 0` checks if the final coordinates are at the origin (0, 0). +1. **Convert Input to Uppercase:** +- `z = input("Enter the directions: ")`: Prompts the user to enter the directions for the robot. The input is stored in the variable `z`. +- `z = z.upper()`: Converts the input string to uppercase, ensuring case-insensitivity. + +7**. Check and Print Result:** + +- `if robot_return_to_origin(z):`: Calls the `robot_return_to_origin` function with the user-input directions and checks if the robot returns to the origin. +- If the robot returns to the origin ,then it returns true orelse it returns false. + +In summary, this Python code prompts the user to input a sequence of directions for a robot (U for up, D for down, R for right, L for left), updates the robot's position accordingly, and then checks if the robot returns to the origin. The result is printed to the user. + +## C++ Code + +```cpp +// Copyrights to venkys.io +// For more programs visit venkys.io +// c++ program for robot return to origin + +#include +#include // For toupper function + +bool robotReturnToOrigin(const std::string &input) +{ + // Initialize the coordinates to (0, 0) + int x = 0, y = 0; + + // Iterate through each character in the input string + for (char i : input) + { + // Update coordinates based on the current direction + if (i == 'U') + { // U denotes "UP" and it moves towards top from the origin(y-axis) + y += 1; + } + else if (i == 'D') + { // D denotes "DOWN" and it moves bottom from the origin(y-axis) + y -= 1; + } + else if (i == 'R') + { // R denotes "RIGHT" and it moves right hand side from the origin(x-axis) + x += 1; + } + else if (i == 'L') + { // L denotes "LEFT" and it moves left hand side from the origin(x-axis) + x -= 1; + } + else + { + // Handle invalid input characters other than "R,U,L,D" + std::cout << "Wrong input" << std::endl; + } + } + + // Check if the final coordinates are at the origin (0, 0) + return x == 0 && y == 0; +} + +int main() +{ + // Get user input for directions (case-insensitive) + std::string z; + // std::cout << "Enter the directions: "; + std::cin >> z; + + // Convert input to uppercase for case-insensitivity + for (char &c : z) + { + c = std::toupper(c); + } + + // Call the function and print the result + std::cout << (robotReturnToOrigin(z) ? "true" : "false") << std::endl; // returns True if the robot returns to the origin else returns False + return 0; +} +``` + +### **Step-by-Step Explanation:** + +**1. Function Definition:** + +- `bool robot_return_to_origin(const string &input)`: This declares a function named `robot_return_to_origin` that takes a constant reference to a string (`const string &input`) as a parameter. The function returns a boolean value (`bool`), indicating whether the robot returns to the origin. The function is designed to process a sequence of directional inputs and determine if the robot returns to the origin (0,0) on a 2D plane. + +**2. Initialize Position:** + +- `int x = 0, y = 0;`: Initializes two integer variables `x` and `y` to zero. These variables represent the current position of the robot on the x-axis and y-axis, respectively. The initial position is set at the origin (0,0). + +**3. Loop Through Input:** + +- `for (char i : input)`: Initiates a range-based for loop that iterates through each character (`char i`) in the input string. The loop allows the program to process each directional input. + +**4. Update Position:** + +- Inside the loop, there is an `if-else` block that updates the robot's position based on the current character: + - `if (i == 'U')`: Increments `y` to move the robot up. + - `else if (i == 'D')`: Decrements `y` to move the robot down. + - `else if (i == 'R')`: Increments `x` to move the robot right. + - `else if (i == 'L')`: Decrements `x` to move the robot left. + - `else`: Prints an error message if the input contains an invalid character and returns `false` to indicate an issue with the input. +- The `return x == 0 && y == 0` checks if the final coordinates are at the origin (0, 0). + +**5. Convert Input to Uppercase:** + +- After processing the directional inputs, the main function converts the entire input string to uppercase: + - `for (char &c : directions) { c = toupper(c); }`: This loop iterates through each character in the `directions` string and converts it to uppercase using the `toupper` function. This ensures case-insensitive comparison. + +**6. Check and Print Result:** + +- `if (robot_return_to_origin(directions))`: Calls the `robot_return_to_origin` function with the processed user-input directions and checks if the robot returns to the origin. +- If the robot returns to the origin ,then it returns true orelse it returns false. + +In summary, this C++ code prompts the user to input a sequence of directions for a robot (U for up, D for down, R for right, L for left), updates the robot's position accordingly, and then checks if the robot returns to the origin. The result is printed to the user, and the program ensures case-insensitivity by converting all input characters to uppercase. + +## Java Code + +```java +// Copyrights to venkys.io +// For more programs visit venkys.io +// Java program for robot return to origin + +import java.util.Scanner; + +public class robotreturn { + + public static boolean isRobotReturnToOrigin(String input) { + int x = 0, y = 0; + for (char i : input.toCharArray()) { + if (i == 'U') { + y += 1; + } else if (i == 'D') { + y -= 1; + } else if (i == 'R') { + x += 1; + } else if (i == 'L') { + x -= 1; + } else { + System.out.println("Wrong input"); + return false; + } + } + return x == 0 && y == 0; + } + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + // System.out.print("Enter the directions: "); + String directions = scanner.nextLine().toUpperCase(); + + if (isRobotReturnToOrigin(directions)) { + System.out.println("true"); + } else { + System.out.println("false"); + } + } +} +``` + +### **Step-by-Step Explanation:** + +**1. Function Definition:** + +- `public static boolean isRobotReturnToOrigin(String input)`: This line declares a static function named `isRobotReturnToOrigin` that takes a string `input` as a parameter. The function returns a boolean value (`true` or `false`), indicating whether the robot returns to the origin. The function processes a sequence of directional inputs and checks if the robot, represented by these inputs, returns to the origin (0,0) on a 2D plane. + +**2. Initialize Position:** + +- `int x = 0, y = 0;`: Initializes two integer variables `x` and `y` to zero. These variables represent the current position of the robot on the x-axis and y-axis, respectively. The initial position is set at the origin (0,0). + +**3. Loop Through Input:** + +- `for (char i : input.toCharArray()) { }`: Initiates a enhanced for loop that iterates through each character (`char i`) in the input string. The `toCharArray()` method converts the input string to an array of characters. + +**4. Update Position:** + +- Inside the loop, there is an `if-else` block that updates the robot's position based on the current character: + - `if (i == 'U')`: Increments `y` to move the robot up. + - `else if (i == 'D')`: Decrements `y` to move the robot down. + - `else if (i == 'R')`: Increments `x` to move the robot right. + - `else if (i == 'L')`: Decrements `x` to move the robot left. + - `else`: Prints an error message if the input contains an invalid character and returns `false` to indicate an issue with the input. +- The `return x == 0 and y == 0` checks if the final coordinates are at the origin (0, 0). + +**5. Convert Input to Uppercase:** + +- `String directions = scanner.nextLine().toUpperCase();`: Reads the user input using a `Scanner` and converts the entire input string to uppercase using the `toUpperCase()` method. This ensures case-insensitive comparison. + +**6. Check and Print Result:** + +- `if (isRobotReturnToOrigin(directions)) { }`: Calls the `isRobotReturnToOrigin` function with the processed user-input directions and checks if the robot returns to the origin. +- If the robot returns to the origin,then it returns true or else it returns false. + +## **Time and Space Complexity Analysis** + +**Time Complexity:** + +- The function iterates through each character in the input string exactly once, performing constant-time operations for each character. +- Therefore, the time complexity is O(n), where n is the length of the input string. + +**Space Complexity:** + +- The function uses only a constant amount of extra space, regardless of the size of the input string. The extra space is used for the integer variables **`x`** and **`y`**. +- Therefore, the space complexity is O(1), indicating constant space usage. + +In summary, the robot return to origin algorithm has a time complexity of O(n) and a space complexity of O(1), where n is the length of the input string. + +## Real world Applications + +The robot return to origin algorithm is a fundamental technique in robotics that allows a robot to navigate back to its starting point without getting lost. It is used in a variety of real-world applications, including: + +- **Autonomous exploration:** Robots that are exploring new environments often use the return to origin algorithm to make sure they can always find their way back to a safe starting point. +- **Mapping and surveying:** Robots that are mapping or surveying an area can use the return to origin algorithm to make sure they cover the entire area without getting lost. +- **Search and rescue:** Robots that are searching for people or objects in a disaster zone can use the return to origin algorithm to make sure they don't get lost and can always find their way back to their base station. +- **Delivery and logistics:** Robots that are delivering goods or performing other logistical tasks can use the return to origin algorithm to make sure they always return to their starting point. +- **Home automation:** Robots that are performing tasks in the home, such as cleaning or vacuuming, can use the return to origin algorithm to make sure they always return to their charging station. + +The return to origin algorithm is a versatile and powerful tool that can be used for a wide variety of robotic tasks. It is a fundamental technique that is essential for the development of autonomous robots. + +The specific implementation of the return to origin algorithm will vary depending on the specific application. However, the general principles are the same: the robot must keep track of its position and orientation, and it must use this information to plan a path back to its starting point. + +The return to origin algorithm can be implemented using a variety of different techniques, such as: + +- **Dead reckoning:** This is the simplest method, and it involves keeping track of the robot's position and orientation by estimating its movement. However, dead reckoning is not very accurate, and it can accumulate errors over time. +- **Landmark navigation:** This method involves using landmarks in the environment to help the robot navigate. The robot can store a map of the landmarks, and it can use this map to plan a path back to its starting point. +- **SLAM (Simultaneous Localization and Mapping):** This is the most sophisticated method, and it involves simultaneously building a map of the environment and estimating the robot's position within that map. SLAM is very accurate, but it is also computationally expensive. + +The choice of which method to use will depend on the specific application and the available resources. + +## Test Cases + +- Input: "UDLRUDDLLUURRR" + Output: False + + Explanation: + + - The robot moves up, down, left, right, up, down, down, left, left, left, up, up, right, right, right. + - The final coordinates are (2, -1), not at the origin. + Therefore, the output is False. + +- Input: "UDRLUD" + Output: True + + Explanation: + + We start at the origin (0, 0). + For each character in the input string: + - "U" (Up): Move one unit up, so the position becomes (0, 1). + - "D" (Down): Move one unit down, so the position becomes (0, 0). + - "R" (Right): Move one unit to the right, so the position becomes (1, 0). + - "L" (Left): Move one unit to the left, so the position becomes (0, 0). + - "U" (Up): Move one unit up, so the position becomes (0, 1). + - "D" (Down): Move one unit down, so the position becomes (0, 0). + After executing all the movements, the robot returns to the origin (0, 0). Therefore, the output is True. diff --git a/Strings/Easy/robot_return_to_origin/robotreturn.cpp b/Strings/Easy/robot_return_to_origin/robotreturn.cpp new file mode 100644 index 00000000..4eba7912 --- /dev/null +++ b/Strings/Easy/robot_return_to_origin/robotreturn.cpp @@ -0,0 +1,56 @@ +#include +#include // For toupper function + +bool robotReturnToOrigin(const std::string &input) +{ + // Initialize the coordinates to (0, 0) + int x = 0, y = 0; + + // Iterate through each character in the input string + for (char i : input) + { + // Update coordinates based on the current direction + if (i == 'U') + { // U denotes "UP" and it moves towards top from the origin(y-axis) + y += 1; + } + else if (i == 'D') + { // D denotes "DOWN" and it moves bottom from the origin(y-axis) + y -= 1; + } + else if (i == 'R') + { // R denotes "RIGHT" and it moves right hand side from the origin(x-axis) + x += 1; + } + else if (i == 'L') + { // L denotes "LEFT" and it moves left hand side from the origin(x-axis) + x -= 1; + } + else + { + // Handle invalid input characters other than "R,U,L,D" + std::cout << "Wrong input" << std::endl; + } + } + + // Check if the final coordinates are at the origin (0, 0) + return x == 0 && y == 0; +} + +int main() +{ + // Get user input for directions (case-insensitive) + std::string z; + std::cout << "Enter the directions: "; + std::cin >> z; + + // Convert input to uppercase for case-insensitivity + for (char &c : z) + { + c = std::toupper(c); + } + + // Call the function and print the result + std::cout << (robotReturnToOrigin(z) ? "true" : "false") << std::endl; // returns True if the robot returns to the origin else returns False + return 0; +} diff --git a/Strings/Easy/robot_return_to_origin/robotreturn.java b/Strings/Easy/robot_return_to_origin/robotreturn.java new file mode 100644 index 00000000..cbf5dd55 --- /dev/null +++ b/Strings/Easy/robot_return_to_origin/robotreturn.java @@ -0,0 +1,41 @@ +import java.util.Scanner; + +public class robotreturn { + public static void main(String[] args) { + try (// Get user input for directions (case-insensitive) + Scanner scanner = new Scanner(System.in)) { + System.out.print("Enter the directions: "); + String z = scanner.nextLine().toUpperCase(); // Convert input to uppercase for case-insensitivity + + // Call the function and print the result + System.out.println(robotReturnToOrigin(z)); // returns True if the robot returns to the origin else returns + // False + + } + } + + static boolean robotReturnToOrigin(String input) { + // Initialize the coordinates to (0, 0) + int x = 0, y = 0; + + // Iterate through each character in the input string + for (char i : input.toCharArray()) { + // Update coordinates based on the current direction + if (i == 'U') { // U denotes "UP" and it moves towards top from the origin(y-axis) + y += 1; + } else if (i == 'D') { // D denotes "DOWN" and it moves bottom from the origin(y-axis) + y -= 1; + } else if (i == 'R') { // R denotes "RIGHT" and it moves right hand side from the origin(x-axis) + x += 1; + } else if (i == 'L') { // L denotes "LEFT" and it moves left hand side from the origin(x-axis) + x -= 1; + } else { + // Handle invalid input characters other than "R,U,L,D" + System.out.println("Wrong input"); + } + } + + // Check if the final coordinates are at the origin (0, 0) + return x == 0 && y == 0; + } +} diff --git a/Strings/Easy/robot_return_to_origin/robotreturn.py b/Strings/Easy/robot_return_to_origin/robotreturn.py new file mode 100644 index 00000000..406dd7a2 --- /dev/null +++ b/Strings/Easy/robot_return_to_origin/robotreturn.py @@ -0,0 +1,29 @@ +def robot_return_to_origin(input): + # Initialize the coordinates to (0, 0) + x = y = 0 + + # Iterate through each character in the input string + for i in input: + # Update coordinates based on the current direction + if i == "U": #U denotes "UP" and it moves towards top from the origin(y-axis) + y += 1 + elif i == "D": #D denotes "DOWN" and it moves bottom from the origin(y-axis) + y -= 1 + elif i == "R": #R denotes "RIGHT" and it moves right hand side from the origin(x-axis) + x += 1 + elif i == "L": #L denotes "LEFT" and it moves left hand side from the origin(x-axis) + x -= 1 + else: + # Handle invalid input characters other than "R,U,L,D" + print("Wrong input") + + # Check if the final coordinates are at the origin (0, 0) + return x == 0 and y == 0 + +# Get user input for directions (case-insensitive) +z = input("Enter the directions: ") +z = z.upper() # Convert input to uppercase for case-insensitivity + +# Call the function and print the result +print(robot_return_to_origin(z)) +#returns True if the robot returns to the origin else returns False \ No newline at end of file diff --git a/Strings/Easy/romantointeger/README.md b/Strings/Easy/romantointeger/README.md new file mode 100644 index 00000000..0afcba5a --- /dev/null +++ b/Strings/Easy/romantointeger/README.md @@ -0,0 +1,310 @@ +# Exploring String Algorithms:Roman to Integer + +Dive into the realm of particular emphasis on uncovering the roman to integer conversion problem through the utilization of string algorithm. This intriguing challenge not only captivates but also offers a practical avenue to delve into the intricacies of data structures and foster algorithmic thinking. + +# Introduction to String Algorithms + +String algorithms, a versatile toolkit for tackling an array of computational challenges. String algorithms, designed for the manipulation and analysis of sequences of characters, are essential in addressing a wide spectrum of problems in computer science. Within this domain, string algorithms prove instrumental in tasks such as pattern matching, substring search, and the optimization of various string-related operations. + +As we explore, we'll know much about fundamental string algorithms, examining techniques like string matching, regular expressions, and dynamic programming. Join this journey into the heart of string manipulation, where the algorithms we encounter will become indispensable tools for deciphering, analyzing, and extracting valuable information from the world of characters and text. + +One of the fundamental case in string algorithms is Robot return to Origin. + +## Roman numerals to Integer + +A Roman numeral to integer algorithm is a method for converting Roman numerals, which are a system of symbols used in ancient Rome to represent numbers, into their corresponding integer values.Roman numerals use a combination of letters from the Latin alphabet (I, V, X, L, C, D, M) to represent numbers.There are two main types of Roman numeral to integer algorithms: subtractive and additive. + +Set a variableto 0 to store the final integer value then start from the leftmost character of the Roman numeral string. Compare the current numeral with the next numeral to determine the appropriate operation (addition or subtraction). + +If the value of the current numeral is less than the value of the next numeral, subtract the current numeral's value from the result.If the value of the current numeral is greater than or equal to the value of the next numeral, add the current numeral's value to the result. + +Here's a simple example: + +Roman numeral: XIV + +Process: X (10) + (V (5) - I (1)) + +Result: 14 + +## Python code + +```python +def roman_to_int(s): + roman_dict = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} +# Define a dictionary mapping Roman numerals to their integer values + result = 0 # Initialize the result variable to store the total integer value + + # Loop through the Roman numeral string from left to right + for i in range(len(s)): + # If the current numeral is smaller than the next numeral, subtract its value + if i < len(s) - 1 and roman_dict[s[i]] < roman_dict[s[i + 1]]: + result -= roman_dict[s[i]] + else: + result += roman_dict[s[i]] + + return result + +# Test the function +roman_numeral = input() +integer_value = roman_to_int(roman_numeral.upper()) +print(integer_value) +``` + +### Step-by-Step Explaination + +1. **Function Definition:** + - **`def roman_to_int(s):`**: This line defines a function named **`roman_to_int`** that takes a string **`s`** representing a Roman numeral as its parameter. +2. **Roman Numeral Dictionary:** + - **`roman_dict = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}`**: This line creates a dictionary (**`roman_dict`**) that maps Roman numeral characters to their corresponding integer values. +3. **Initialization:** + - **`result = 0`**: This line initializes a variable **`result`** to store the total integer value, starting with 0. +4. **Loop through the Roman Numeral String:** + - **`for i in range(len(s)):`**: This line starts a loop that iterates through each character in the input Roman numeral string. +5. **Check for Subtraction Rule:** + - **`if i < len(s) - 1 and roman_dict[s[i]] < roman_dict[s[i + 1]]:`**: This line checks if the current numeral is smaller than the next numeral. If true, it means that the subtraction rule applies. +6. **Subtract or Add Values:** + - **`result -= roman_dict[s[i]]`**: If the condition is true, subtract the current numeral's value from the result. + - **`else: result += roman_dict[s[i]]`**: If the condition is false, add the current numeral's value to the result. +7. **Return Result:** + - **`return result`**: After the loop completes, the function returns the final calculated integer value. +8. **Test the Function:** + - **`roman_numeral = input("Enter a Roman numeral: ")`**: This line prompts the user to enter a Roman numeral. + - **`integer_value = roman_to_int(roman_numeral.upper())`**: The function is called with the input Roman numeral (converted to uppercase for case-insensitivity), and the result is stored in **`integer_value`**. + - **`print(f"The integer value of {roman_numeral} is: {integer_value}")`**: The program prints the final result. + + ## C++ code + + ```cpp + #include + #include + + int romanToInt(const std::string &s) + { + // Define a unordered_map mapping Roman numerals to their integer values + std::unordered_map romanMap{ + {'I', 1}, + {'V', 5}, + {'X', 10}, + {'L', 50}, + {'C', 100}, + {'D', 500}, + {'M', 1000}}; + + int result = 0; // Initialize the result variable to store the total integer value + + // Loop through the Roman numeral string from left to right + for (int i = 0; i < s.length(); ++i) + { + // If the current numeral is smaller than the next numeral, subtract its value + if (i < s.length() - 1 && romanMap[s[i]] < romanMap[s[i + 1]]) + { + result -= romanMap[s[i]]; + } + else + { + result += romanMap[s[i]]; + } + } + + return result; + } + + int main() + { + // Test the function + std::string romanNumeral; + // std::cout << "Enter a Roman numeral: "; + std::cin >> romanNumeral; + + int integerValue = romanToInt(romanNumeral); + std::cout << integerValue << std::endl; + + return 0; + } + ``` + + ### Step-by-Step explaination + + 1. **Include Headers:** + - **`#include `**: This line includes the input/output stream library, which is needed for input and output operations. + - **`#include `**: This line includes the unordered map library, which is used to define the mapping of Roman numerals to integers. + 2. **Function Definition:** + - **`int romanToInt(const std::string &s)`**: This line defines a function named **`romanToInt`** that takes a constant reference to a string **`s`** as its parameter and returns an integer. + 3. **Roman Numeral Dictionary:** + - **`std::unordered_map romanMap{ ... }`**: This line creates an unordered_map (**`romanMap`**) that maps Roman numeral characters to their corresponding integer values. + 4. **Initialization:** + - **`int result = 0;`**: This line initializes a variable **`result`** to store the total integer value, starting with 0. + 5. **Loop through the Roman Numeral String:** + - **`for (int i = 0; i < s.length(); ++i)`**: This line starts a loop that iterates through each character in the input Roman numeral string. + 6. **Check for Subtraction Rule:** + - **`if (i < s.length() - 1 && romanMap[s[i]] < romanMap[s[i + 1]])`**: This line checks if the current numeral is smaller than the next numeral. If true, it means that the subtraction rule applies. + 7. **Subtract or Add Values:** + - **`result -= romanMap[s[i]];`**: If the condition is true, subtract the current numeral's value from the result. + - **`else: result += romanMap[s[i]];`**: If the condition is false, add the current numeral's value to the result. + 8. **User Input and Function Call:** + - **`std::string romanNumeral;`**: This line declares a string variable to store the user's input. + - **`std::cout << "Enter a Roman numeral: ";`**: This line prints a prompt asking the user to enter a Roman numeral. + - **`std::cin >> romanNumeral;`**: This line takes user input and stores it in the **`romanNumeral`** variable. + - **`int integerValue = romanToInt(romanNumeral);`**: The **`romanToInt`** function is called with the input Roman numeral, and the result is stored in the **`integerValue`** variable. + + ## Java code + + ```java + import java.util.HashMap; + import java.util.Map; + import java.util.Scanner; + + public class romantoint { + + public static int romanToInt(String s) { + // Define a map mapping Roman numerals to their integer values + Map romanMap = new HashMap<>(); + romanMap.put('I', 1); + romanMap.put('V', 5); + romanMap.put('X', 10); + romanMap.put('L', 50); + romanMap.put('C', 100); + romanMap.put('D', 500); + romanMap.put('M', 1000); + + int result = 0; // Initialize the result variable to store the total integer value + + // Loop through the Roman numeral string from left to right + for (int i = 0; i < s.length(); i++) { + // If the current numeral is smaller than the next numeral, subtract its value + if (i < s.length() - 1 && romanMap.get(s.charAt(i)) < romanMap.get(s.charAt(i + 1))) { + result -= romanMap.get(s.charAt(i)); + } else { + result += romanMap.get(s.charAt(i)); + } + } + + return result; + } + + public static void main(String[] args) { + try (// Test the function + Scanner scanner = new Scanner(System.in)) { + // System.out.print("Enter a Roman numeral: "); + String romanNumeral = scanner.nextLine(); + + int integerValue = romanToInt(romanNumeral.toUpperCase()); + System.out.println(integerValue); + } + } + } + ``` + + ### Step-by-Step explaination + + 1. **Import Statements:** + - **`import java.util.HashMap;`**: Import the **`HashMap`** class from the **`java.util`** package for creating a map. + - **`import java.util.Map;`**: Import the **`Map`** interface for working with maps. + - **`import java.util.Scanner;`**: Import the **`Scanner`** class for taking user input. + 2. **Class Declaration:** + - **`public class romantoint { ... }`**: Define a class named **`romantoint`**. + 3. **Function Definition:** + - **`public static int romanToInt(String s) { ... }`**: Define a function named **`romanToInt`** that takes a string **`s`** as a parameter and returns an integer. + 4. **Roman Numeral Map:** + - **`Map romanMap = new HashMap<>();`**: Create a map (**`romanMap`**) mapping Roman numeral characters to their corresponding integer values. + 5. **Initialization:** + - **`int result = 0;`**: Initialize a variable **`result`** to store the total integer value, starting with 0. + 6. **Loop through the Roman Numeral String:** + - **`for (int i = 0; i < s.length(); i++) { ... }`**: Loop through each character in the input Roman numeral string. + 7. **Check for Subtraction Rule:** + - **`if (i < s.length() - 1 && romanMap.get(s.charAt(i)) < romanMap.get(s.charAt(i + 1))) { ... }`**: Check if the current numeral is smaller than the next numeral. If true, it means that the subtraction rule applies. + 8. **Subtract or Add Values:** + - **`result -= romanMap.get(s.charAt(i));`**: If the condition is true, subtract the current numeral's value from the result. + - **`else: result += romanMap.get(s.charAt(i));`**: If the condition is false, add the current numeral's value to the result. + 9. **Return Result:** + - **`return result;`**: After the loop completes, the function returns the final calculated integer value. + 10. **Main Method:** + - **`public static void main(String[] args) { ... }`**: Define the main method, the entry point of the program. + 1. **Try-with-Resources and User Input:** + - **`try (Scanner scanner = new Scanner(System.in)) { ... }`**: Use try-with-resources to automatically close the **`Scanner`** after it is used. + - **`System.out.print("Enter a Roman numeral: ");`**: Print a prompt asking the user to enter a Roman numeral. + - **`String romanNumeral = scanner.nextLine();`**: Take user input and store it in the **`romanNumeral`** variable. + 2. **Function Call and Result Output:** + - **`int integerValue = romanToInt(romanNumeral.toUpperCase());`**: Call the **`romanToInt`** function with the input Roman numeral (converted to uppercase for consistency). + - **`System.out.println("The integer value of " + romanNumeral + " is: " + integerValue);`**: Print the final result. + + ## **Time and Space Complexity Analysis** + + ### **Python Code:** + + **Time Complexity:** + + - The time complexity of the code is O(n), where n is the length of the input Roman numeral string. The algorithm iterates through the string once. + + **Space Complexity:** + + - The space complexity is O(1). The additional space used is constant regardless of the input size, as there is no dynamic data structure that grows with the input. + + ### **C++ Code:** + + **Time Complexity:** + + - Similar to the Python code, the time complexity is O(n), where n is the length of the input Roman numeral string. The algorithm iterates through the string once. + + **Space Complexity:** + + - The space complexity is O(1), as it uses a fixed amount of space for the result variable and the loop index. The **`std::unordered_map`** used for mapping Roman numerals to integers has a constant number of entries. + + ### **Java Code:** + + **Time Complexity:** + + - Again, the time complexity is O(n), where n is the length of the input Roman numeral string. The algorithm iterates through the string once. + + **Space Complexity:** + + - Similar to the other implementations, the space complexity is O(1). The space used is constant, except for the map (**`HashMap`**), which has a constant number of entries. + + The time complexity for all implementations is O(n), and the space complexity is O(1) because the additional space used is constant and does not depend on the input size. The key factor contributing to the linear time complexity is the single loop that iterates through the input Roman numeral string. The space complexity remains constant because the additional memory used is fixed, regardless of the size of the input. + + ## Real world Applications + + While the Roman to integer algorithm may not have direct real-life applications for general end-users, it plays a role in software development and certain specialized areas. Here are a few scenarios where the Roman to integer algorithm might be applied: + + 1. **Historical Data Processing:** + - In historical research or data analysis involving ancient documents or artifacts, Roman numerals might be used. Converting Roman numerals to integers can help researchers perform quantitative analyses or comparisons. + 2. **Library Cataloging Systems:** + - Some library cataloging systems or databases might use Roman numerals for classification or organization. Converting Roman numerals to integers can facilitate sorting and searching algorithms. + 3. **Educational Software:** + - Educational software or games that involve Roman numerals may use the algorithm to check the correctness of a user's input or to provide feedback on Roman numeral-related exercises. + 4. **Financial Systems:** + - In financial applications, especially those dealing with historical financial records, Roman numerals might be encountered. Converting these numerals to integers can assist in performing financial calculations or analyses. + 5. **Legal Documents:** + - Certain legal or official documents, especially those with a traditional or formal tone, may use Roman numerals for section numbering or other purposes. Converting them to integers can be helpful in automated document processing. + 6. **Parsing and Data Extraction:** + - In text processing applications, the algorithm can be used to extract and convert Roman numerals from textual data. This could be useful in data parsing or natural language processing tasks. + 7. **Quiz and Game Applications:** + - Educational quizzes, games, or trivia apps that involve questions related to Roman numerals may use the algorithm to validate user responses. + 8. **Symbolic Representations in Software Development:** + - In certain programming contexts, Roman numerals might be used symbolically, and the algorithm could be employed for internal data processing within the software. + + While the direct application of the Roman to integer algorithm might be limited in day-to-day activities, it serves as a foundational component in various software-related tasks, historical research, and specific academic or niche areas where Roman numerals are still relevant. + + ## Test Cases + - Input: "XIV" + Output: 24 + + Explanation: + - "X" is 10, "I" is 1, and "V" is 5. + - Since "I" is smaller than "V" following it, it should be subtracted. So, "IX" is 9. + - "X" is 10. + - "IV" is 4. + - Adding these values, the total is 10 + 9 + 5 + 1 = 24. + + The function roman_to_int processes the input string "XIV" according to the Roman numeral rules and returns the integer value 24. + - Input: "MMXXI" + Output: 2009 + + Explanation: + - "M" is 1000, "M" is 1000, "X" is 10, "X" is 10, and "I" is 1. + - Since "M" is not smaller than "M" following it, both "M"s contribute to the total as 1000 + 1000 = 2000. + - "X" is not smaller than "X" following it, so it contributes 10. + - "I" is smaller than "X" following it, so it is subtracted, contributing -1. + - Adding these values, the total is 2000 + 10 - 1 = 2009. + + The function roman_to_int processes the input string "MMXXI" according to the Roman numeral rules and returns the integer value 2009. diff --git a/Strings/Easy/romantointeger/romantoint.cpp b/Strings/Easy/romantointeger/romantoint.cpp new file mode 100644 index 00000000..95ca0a6f --- /dev/null +++ b/Strings/Easy/romantointeger/romantoint.cpp @@ -0,0 +1,46 @@ +#include +#include + +int romanToInt(const std::string &s) +{ + // Define a unordered_map mapping Roman numerals to their integer values + std::unordered_map romanMap{ + {'I', 1}, + {'V', 5}, + {'X', 10}, + {'L', 50}, + {'C', 100}, + {'D', 500}, + {'M', 1000}}; + + int result = 0; // Initialize the result variable to store the total integer value + + // Loop through the Roman numeral string from left to right + for (int i = 0; i < s.length(); ++i) + { + // If the current numeral is smaller than the next numeral, subtract its value + if (i < s.length() - 1 && romanMap[s[i]] < romanMap[s[i + 1]]) + { + result -= romanMap[s[i]]; + } + else + { + result += romanMap[s[i]]; + } + } + + return result; +} + +int main() +{ + // Test the function + std::string romanNumeral; + std::cout << "Enter a Roman numeral: "; + std::cin >> romanNumeral; + + int integerValue = romanToInt(romanNumeral); + std::cout << "The integer value of " << romanNumeral << " is: " << integerValue << std::endl; + + return 0; +} diff --git a/Strings/Easy/romantointeger/romantoint.java b/Strings/Easy/romantointeger/romantoint.java new file mode 100644 index 00000000..579bc6eb --- /dev/null +++ b/Strings/Easy/romantointeger/romantoint.java @@ -0,0 +1,43 @@ +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +public class romantoint { + + public static int romanToInt(String s) { + // Define a map mapping Roman numerals to their integer values + Map romanMap = new HashMap<>(); + romanMap.put('I', 1); + romanMap.put('V', 5); + romanMap.put('X', 10); + romanMap.put('L', 50); + romanMap.put('C', 100); + romanMap.put('D', 500); + romanMap.put('M', 1000); + + int result = 0; // Initialize the result variable to store the total integer value + + // Loop through the Roman numeral string from left to right + for (int i = 0; i < s.length(); i++) { + // If the current numeral is smaller than the next numeral, subtract its value + if (i < s.length() - 1 && romanMap.get(s.charAt(i)) < romanMap.get(s.charAt(i + 1))) { + result -= romanMap.get(s.charAt(i)); + } else { + result += romanMap.get(s.charAt(i)); + } + } + + return result; + } + + public static void main(String[] args) { + try (// Test the function + Scanner scanner = new Scanner(System.in)) { + System.out.print("Enter a Roman numeral: "); + String romanNumeral = scanner.nextLine(); + + int integerValue = romanToInt(romanNumeral.toUpperCase()); + System.out.println("The integer value of " + romanNumeral + " is: " + integerValue); + } + } +} diff --git a/Strings/Easy/romantointeger/romantoint.py b/Strings/Easy/romantointeger/romantoint.py new file mode 100644 index 00000000..dcd3923a --- /dev/null +++ b/Strings/Easy/romantointeger/romantoint.py @@ -0,0 +1,19 @@ +def roman_to_int(s): + # Define a dictionary mapping Roman numerals to their integer values + roman_dict = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + result = 0# Initialize the result variable to store the total integer value + + # Loop through the Roman numeral string from left to right + for i in range(len(s)): + # If the current numeral is smaller than the next numeral, subtract its value + if i < len(s) - 1 and roman_dict[s[i]] < roman_dict[s[i + 1]]: + result -= roman_dict[s[i]] + else: + result += roman_dict[s[i]] + + return result + +# Test the function +roman_numeral = input("Enter a Roman numeral: ") +integer_value = roman_to_int(roman_numeral.upper()) +print(f"The integer value of {roman_numeral} is: {integer_value}") diff --git a/Strings/Medium/Largest number/README.md b/Strings/Medium/Largest number/README.md new file mode 100644 index 00000000..16ac7961 --- /dev/null +++ b/Strings/Medium/Largest number/README.md @@ -0,0 +1,545 @@ +# **Exploring String Algorithms : Largest Number** + +Dive into the realm of particular emphasis on uncovering the largest number problem through the utilization of string algorithm. This intriguing challenge not only captivates but also offers a practical avenue to delve into the intricacies of data structures and foster algorithmic thinking. + +# Introduction to String Algorithms + +String algorithms, a versatile toolkit for tackling an array of computational challenges. String algorithms, designed for the manipulation and analysis of sequences of characters, are essential in addressing a wide spectrum of problems in computer science. Within this domain, string algorithms prove instrumental in tasks such as pattern matching, substring search, and the optimization of various string-related operations. + +As we explore, we'll know much about fundamental string algorithms, examining techniques like string matching, regular expressions, and dynamic programming. Join this journey into the heart of string manipulation, where the algorithms we encounter will become indispensable tools for deciphering, analyzing, and extracting valuable information from the world of characters and text. + +One of the case in string algorithms is Largest number. + +## Largest Number + +The provided Python code aims to find the largest number that can be formed by concatenating a list of integers. This is achieved through a custom comparison function used in the sorting process. The goal is to arrange the integers in a way that, when concatenated, results in the maximum possible numerical value. + +## Python Code + +```python +import functools as f + +# Custom comparison function for sorting strings +def compare(x, y): + return (x < y) - (x > y) + +# Function to find the largest number by concatenating elements of the list +def largestNumber(nums): + # Convert the list of integers to a list of strings + arr = list(map(str, nums)) + + # Sort the list of strings using a custom comparison function + arr.sort(key=f.cmp_to_key(lambda x, y: compare(x + y, y + x))) + + # Join the sorted strings, remove leading zeros, or return "0" if the result is empty + return "".join(arr).lstrip("0") or "0" + +# Main block +if __name__ == "__main__": + # Convert the input string to a list of integers + nums=[int(x) for x in input().split(" ")] + # print the list + print(nums) + # Call the function and print the result + result = largestNumber(nums) + print(result) + +# Enter multiple value: 21 23 43 56 9 98 +# [21, 23, 43, 56, 9, 98] +# The largest number is: 99856432321 +``` + +### Step-by-Step Explaination: + +1. **Import Statement:** + + ```python + import functools as f + ``` + + This line imports the **`functools`** module and aliases it as **`f`** for brevity. + +2. **Custom Comparison Function:** + + ```python + def compare(x, y): + return (x < y) - (x > y) + ``` + + The **`compare`** function is a custom comparison function that returns **`-1`** if **`x`** is less than **`y`**, **`0`** if they are equal, and **`1`** if **`x`** is greater than **`y`**. + +3. **`largestNumber` Function:** + + ```python + def largestNumber(nums): + ``` + + This function takes a list of integers (**`nums`**) as input and returns a string representing the largest number formed by concatenating the elements. + + ```python + arr = list(map(str, nums)) + ``` + + The list comprehension converts each integer in **`nums`** to a string, creating a new list **`arr`** of strings. + + ```python + arr.sort(key=f.cmp_to_key(lambda x, y: compare(x + y, y + x))) + ``` + + The **`sort`** method is used to sort the list of strings using a custom key function. The key function, created using **`cmp_to_key`**, compares the concatenation of **`x + y`** and **`y + x`**, ensuring the list is sorted in a way that maximizes the concatenated value. + + ```python + return "".join(arr).lstrip("0") or "0" + ``` + + The sorted strings are joined into a single string, leading zeros are removed using **`lstrip("0")`**, and if the result is empty, "0" is returned. + +4. **Main Block:** + + ```python + if __name__ == "__main__": + ``` + + This conditional statement checks if the script is being run as the main program. + + ```python + nums = [int(x) for x in input("Enter multiple values: ").split(" ")] + ``` + + The user is prompted to enter multiple values separated by spaces. The input string is then split into a list of integers. + + ```python + print(nums) + ``` + + The list of integers is printed to the console. + + ```python + result = largestNumber(nums) + print(f"The largest number is: {result}") + ``` + + The **`largestNumber`** function is called with the list of integers, and the result is printed to the console. + + +## C++ Code + +```cpp +#include +#include +#include +#include // Add this line to include the necessary header for to_string + +std::string largestnumber(std::vector &num) +{ + // Convert each integer to a string and store in a vector + std::vector arr; + for (auto i : num) + arr.push_back(std::to_string(i)); + + // Sort the strings in descending order based on their concatenated values + std::sort(begin(arr), end(arr), [](const std::string &s1, const std::string &s2) + { return s1 + s2 > s2 + s1; }); + + // Concatenate the sorted strings to form the largest number + std::string res; + for (auto s : arr) + res += s; + + // Remove leading zeros, except when the result is "0" + while (res[0] == '0' && res.length() > 1) + res.erase(0, 1); + + // Return the result as a string + return res; +} + +int main() +{ + // Prompt the user to enter multiple values separated by space + // std::cout << "Enter multiple values separated by space, and press Enter:"; + + // Create a vector to store the input numbers + std::vector arr; + int num; + + // Read input until a newline character is encountered + while (std::cin >> num) + { + // Add the entered number to the vector + arr.push_back(num); + + // Check for newline character + if (std::cin.peek() == '\n') + { + break; + } + } + + // Find and display the largest number + std::cout << largestnumber(arr) << std::endl; + + // Return 0 to indicate successful execution + return 0; +} + +// Enter multiple values separated by space, and press Enter:21 23 34 54 9 98 987 +// The largest number is: 99898754342321 +``` + +### Step-by-Step Explaination: + +1. **``**: This header file provides functionality for input and output operations using streams. It includes declarations for **`cin`** (standard input stream) and **`cout`** (standard output stream), among other things.**``**: This header file includes declarations for the C++ Standard Template Library (STL) vector container. Vectors are dynamic arrays that can grow or shrink in size, making them useful for storing sequences of elements.**``**: This header file includes declarations for various template functions that operate on ranges of elements, such as sorting, searching, and manipulating algorithms. In this code, it is used for the **`std::sort`** function +2. **`largestNumber` Function:** + + **Function Signature:** + +```cpp +std::string largestNumber(std::vector& num) +``` + +This function takes a reference to a vector of integers and returns a string. + + **Conversion to Strings:** + +```cpp +std::vector arr; +for (auto i : num) + arr.push_back(std::to_string(i)); +``` + +It converts each integer in the input vector (**`num`**) to a string and stores them in a new vector (**`arr`**). + + **Sorting:** + +```cpp +std::sort(begin(arr), end(arr), [](const std::string& s1, const std::string& s2) + { return s1 + s2 > s2 + s1; }); +``` + +The strings in the **`arr`** vector are sorted in descending order based on their concatenated values. This custom sorting is achieved using a lambda function as the comparison criterion. + + **Concatenation:** + +```cpp +std::string res; +for (auto s : arr) + res += s; +``` + +The sorted strings are concatenated to form a single string (**`res`**), representing the largest number. + + **Leading Zeros Removal:** + +```cpp +while (res[0] == '0' && res.length() > 1) + res.erase(0, 1); +``` + +Leading zeros are removed from the resulting string, except when the result is "0". + + **Return Statement:** + +```cpp +return res; +``` + +The final result, representing the largest number, is returned as a string. + +1. **`main` Function:** + + **User Input:** + +```cpp +std::vector arr; +int num; +while (std::cin >> num) +{ + arr.push_back(num); + if (std::cin.peek() == '\n') + { + break; + } +} +``` + +The program prompts the user to enter multiple values separated by space and reads these values into a vector (**`arr`**). It continues reading until a newline character is encountered. + + **Function Call and Output:** + +```cpp +std::cout << "The largest number is: " << largestNumber(arr) << std::endl; +``` + +The **`largestNumber`** function is called with the vector of input numbers (**`arr`**), and the result (largest number) is displayed to the console. + + **Return Statement:** + +```cpp +return 0; +``` + +The **`main`** function returns 0 to indicate successful program execution. + +## Java Code + +```java +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Scanner; + +public class largestnumber { + + // Function to find the largest number by concatenating elements of the array + static String largestNumber(int[] nums) { + // Convert the array of integers to an ArrayList of strings + ArrayList arr = new ArrayList<>(); + for (int i : nums) { + arr.add(String.valueOf(i)); + } + + // Define a custom comparator for sorting strings + Comparator comp = (str1, str2) -> (str2 + str1).compareTo(str1 + str2); + + // Sort the ArrayList using the custom comparator + Collections.sort(arr, comp); + + // Build the result by appending non-zero strings + StringBuilder ans = new StringBuilder(); + arr.forEach((s) -> { + if (!s.equals("0")) { + ans.append(s); + } + }); + + // Return the result as a string + return ans.toString(); + } + + public static void main(String[] args) { + try (Scanner scanner = new Scanner(System.in)) { + // Prompt the user to enter the size of the array + // System.out.print("Enter the size of the array: "); + int size = scanner.nextInt(); + + // Prompt the user to enter elements of the array + // System.out.println("Enter the elements of the array:"); + + int[] nums = new int[size]; + for (int i = 0; i < size; i++) { + nums[i] = scanner.nextInt(); + } + + // Find and display the largest number + System.out.println( largestNumber(nums)); + } catch (Exception e) { + // Handle exceptions such as non-integer input + e.printStackTrace(); + } + } +} + +// Enter the size of the array: 5 +// Enter the elements of the array: +// 21 23 43 9 98 +// The largest number is: 998432321 +``` + +### Step-by-Step Explaination: + +1. **Import Statements:** + + ```java + import java.util.ArrayList; + import java.util.Collections; + import java.util.Comparator; + import java.util.Scanner; + ``` + + These lines import necessary classes for working with ArrayLists, sorting, custom comparators, and user input. + +2. **Class Declaration:** + + ```java + public class largestnumber { + ``` + + This line declares a class named **`largestnumber`**. + +3. **`largestNumber` Method:** + + ```java + static String largestNumber(int[] nums) { + ``` + + This method takes an array of integers as input and returns a string representing the largest number formed by concatenating the elements. + + ```java + ArrayList arr = new ArrayList<>(); + for (int i : nums) { + arr.add(String.valueOf(i)); + } + ``` + + The method starts by converting the array of integers into an ArrayList of strings. + + ```java + Comparator comp = (str1, str2) -> (str2 + str1).compareTo(str1 + str2); + ``` + + Next, a custom comparator (**`comp`**) is defined using a lambda expression. This comparator is used to sort the strings in a way that maximizes their concatenated value. + + ```java + Collections.sort(arr, comp); + ``` + + The ArrayList of strings is then sorted using the custom comparator. + + ```java + StringBuilder ans = new StringBuilder(); + arr.forEach((s) -> { + if (!s.equals("0")) { + ans.append(s); + } + }); + ``` + + A **`StringBuilder`** (**`ans`**) is used to build the result by appending non-zero strings from the sorted ArrayList. + + ```java + return ans.toString(); + ``` + + The final result is converted to a string and returned. + +4. **`main` Method:** + + ```java + public static void main(String[] args) { + ``` + + The main method is the entry point of the program. + + ```java + try (Scanner scanner = new Scanner(System.in)) { + ``` + + The **`try`** block initializes a **`Scanner`** for user input. + + ```java + System.out.print("Enter the size of the array: "); + int size = scanner.nextInt(); + ``` + + The user is prompted to enter the size of the array, and the input is stored in the variable **`size`**. + + ```java + System.out.println("Enter the elements of the array:"); + ``` + + The user is prompted to enter the elements of the array. + + ```java + int[] nums = new int[size]; + for (int i = 0; i < size; i++) { + nums[i] = scanner.nextInt(); + } + ``` + + An array **`nums`** is created with the specified size, and the user is prompted to enter each element, which is stored in the array. + + ```java + System.out.println("The largest number is: " + largestNumber(nums)); + ``` + + The **`largestNumber`** method is called with the array as an argument, and the result is printed to the console. + + ```java + } catch (Exception e) { + e.printStackTrace(); + } + ``` + + The **`catch`** block catches any exceptions that might occur during user input and prints the stack trace. + + +## Time and Space Complexity Analysis + +### Time Complexity : + +- The dominant factor contributing to the time complexity is the sorting operation. +- The **`sort`** method uses a variant of TimSort, which is a hybrid sorting algorithm derived from merge sort and insertion sort. +- The time complexity for sorting is O(n log n), where n is the number of elements in the input array. + +### Space Complexity : + +- Additional space is used for the ArrayList **`arr`** to store string representations of integers. +- The space complexity is O(n), where n is the number of elements in the input array. + +In summary, the time complexity for sorting in all three languages is O(n log n), and the space complexity is O(n). + +## Real world Applications + +This type of problem has various real-world applications, especially in scenarios where arranging numbers in a specific way is crucial. Here are some examples: + +1. **Financial Transactions:** + - In finance, when dealing with currency or stock prices, arranging numbers to form the largest or smallest possible value can be important. This can impact decisions related to investments, trading, or financial analysis. +2. **Telecommunications:** + - In telecommunications, phone numbers often need to be sorted or arranged in a specific order. The largest possible arrangement might be important for certain applications or services. +3. **Job Scheduling:** + - In job scheduling or task optimization, arranging tasks based on certain criteria can be crucial. For example, scheduling jobs based on their execution time or priority can be seen as arranging numbers to achieve optimal results. +4. **Version Numbers:** + - When working with software version numbers, arranging them in a way that reflects the latest or highest version is common. This is relevant in software development and release management. +5. **Genetic Sequencing:** + - In bioinformatics, when working with genetic sequences represented as numbers, arranging them in a certain way may have significance for analysis or comparison. +6. **Database Sorting:** + - Sorting or arranging records in databases is a common operation. In some cases, sorting based on a combination of fields, similar to concatenating strings, can be important. +7. **Digital Marketing:** + - When dealing with metrics like click-through rates or conversion rates in digital marketing, arranging or sorting these numbers in a certain order can be valuable for analysis and decision-making. +8. **Supply Chain Management:** + - In logistics and supply chain management, arranging shipments or orders based on criteria like cost, delivery time, or priority can be essential for efficient operations. +9. **Data Analytics:** + - In data analytics, arranging data points based on specific criteria can help identify trends, outliers, or patterns more effectively. +10. **Mobile Number Formatting:** + - In telecommunications and contact management applications, arranging mobile numbers in a way that reflects a standardized or optimal format can be useful. + +These are just a few examples, and the applicability of the code depends on specific use cases where arranging or sorting numbers is an important aspect of the problem at hand. + +## Test Cases + +Test Case 1: + +Input: +21 23 34 54 9 98 987 + +Output: +99898754342321 + +Explanation: +The program prompts the user to enter multiple integer values separated by spaces. +The input numbers are stored in a vector. +The largestnumber function is called with the vector of numbers as input. +Inside the largestnumber function, each integer is converted to a string and stored in a vector. +The strings are sorted in descending order based on their concatenated values. +The sorted strings are concatenated to form the largest number. +Leading zeros are removed from the result, except when the result is "0". +The largest number is then displayed as output. + +Test Case 2: + +Input: +5 56 566 5666 56665 566654 + +Output: +566655665656656566 + +Explanation: +The program prompts the user to enter multiple integer values separated by spaces. +The input numbers are stored in a vector. +The largestnumber function is called with the vector of numbers as input. +Inside the largestnumber function, each integer is converted to a string and stored in a vector. +The strings are sorted in descending order based on their concatenated values. +The sorted strings are concatenated to form the largest number. +Leading zeros are removed from the result, except when the result is "0". +The largest number is then displayed as output. diff --git a/Strings/Medium/Largest number/largestnumber.cpp b/Strings/Medium/Largest number/largestnumber.cpp new file mode 100644 index 00000000..7ad2915c --- /dev/null +++ b/Strings/Medium/Largest number/largestnumber.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include // Add this line to include the necessary header for to_string + +std::string largestnumber(std::vector &num) +{ + // Convert each integer to a string and store in a vector + std::vector arr; + for (auto i : num) + arr.push_back(std::to_string(i)); + + // Sort the strings in descending order based on their concatenated values + std::sort(begin(arr), end(arr), [](const std::string &s1, const std::string &s2) + { return s1 + s2 > s2 + s1; }); + + // Concatenate the sorted strings to form the largest number + std::string res; + for (auto s : arr) + res += s; + + // Remove leading zeros, except when the result is "0" + while (res[0] == '0' && res.length() > 1) + res.erase(0, 1); + + // Return the result as a string + return res; +} + +int main() +{ + // Prompt the user to enter multiple values separated by space + std::cout << "Enter multiple values separated by space, and press Enter:"; + + // Create a vector to store the input numbers + std::vector arr; + int num; + + // Read input until a newline character is encountered + while (std::cin >> num) + { + // Add the entered number to the vector + arr.push_back(num); + + // Check for newline character + if (std::cin.peek() == '\n') + { + break; + } + } + + // Find and display the largest number + std::cout << "The largest number is: " << largestnumber(arr) << std::endl; + + // Return 0 to indicate successful execution + return 0; +} + +// Enter multiple values separated by space, and press Enter:21 23 34 54 9 98 987 +// The largest number is: 99898754342321 \ No newline at end of file diff --git a/Strings/Medium/Largest number/largestnumber.java b/Strings/Medium/Largest number/largestnumber.java new file mode 100644 index 00000000..0a9be16d --- /dev/null +++ b/Strings/Medium/Largest number/largestnumber.java @@ -0,0 +1,60 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Scanner; + +public class largestnumber { + + // Function to find the largest number by concatenating elements of the array + static String largestNumber(int[] nums) { + // Convert the array of integers to an ArrayList of strings + ArrayList arr = new ArrayList<>(); + for (int i : nums) { + arr.add(String.valueOf(i)); + } + + // Define a custom comparator for sorting strings + Comparator comp = (str1, str2) -> (str2 + str1).compareTo(str1 + str2); + + // Sort the ArrayList using the custom comparator + Collections.sort(arr, comp); + + // Build the result by appending non-zero strings + StringBuilder ans = new StringBuilder(); + arr.forEach((s) -> { + if (!s.equals("0")) { + ans.append(s); + } + }); + + // Return the result as a string + return ans.toString(); + } + + public static void main(String[] args) { + try (Scanner scanner = new Scanner(System.in)) { + // Prompt the user to enter the size of the array + System.out.print("Enter the size of the array: "); + int size = scanner.nextInt(); + + // Prompt the user to enter elements of the array + System.out.println("Enter the elements of the array:"); + + int[] nums = new int[size]; + for (int i = 0; i < size; i++) { + nums[i] = scanner.nextInt(); + } + + // Find and display the largest number + System.out.println("The largest number is: " + largestNumber(nums)); + } catch (Exception e) { + // Handle exceptions such as non-integer input + e.printStackTrace(); + } + } +} + +// Enter the size of the array: 5 +// Enter the elements of the array: +// 21 23 43 9 98 +// The largest number is: 998432321 \ No newline at end of file diff --git a/Strings/Medium/Largest number/largestnumber.py b/Strings/Medium/Largest number/largestnumber.py new file mode 100644 index 00000000..a9c98fef --- /dev/null +++ b/Strings/Medium/Largest number/largestnumber.py @@ -0,0 +1,30 @@ +import functools as f + +# Custom comparison function for sorting strings +def compare(x, y): + return (x < y) - (x > y) + +# Function to find the largest number by concatenating elements of the list +def largestNumber(nums): + # Convert the list of integers to a list of strings + arr = list(map(str, nums)) + + # Sort the list of strings using a custom comparison function + arr.sort(key=f.cmp_to_key(lambda x, y: compare(x + y, y + x))) + + # Join the sorted strings, remove leading zeros, or return "0" if the result is empty + return "".join(arr).lstrip("0") or "0" + +# Main block +if __name__ == "__main__": + # Convert the input string to a list of integers + nums=[int(x) for x in input("Enter multiple value: ").split(" ")] + # print the list + print(nums) + # Call the function and print the result + result = largestNumber(nums) + print(f"The largest number is: {result}") + +# Enter multiple value: 21 23 43 56 9 98 +# [21, 23, 43, 56, 9, 98] +# The largest number is: 99856432321 \ No newline at end of file diff --git a/Strings/Medium/Shuffle String/README.md b/Strings/Medium/Shuffle String/README.md new file mode 100644 index 00000000..1b1bc4b0 --- /dev/null +++ b/Strings/Medium/Shuffle String/README.md @@ -0,0 +1,559 @@ +# **Exploring String Algorithms : Shuffle String** + +Dive into the realm of particular emphasis on uncovering the shuffle string problem through the utilization of string algorithm. This intriguing challenge not only captivates but also offers a practical avenue to delve into the intricacies of data structures and foster algorithmic thinking. + +# Introduction to String Algorithms + +String algorithms, a versatile toolkit for tackling an array of computational challenges. String algorithms, designed for the manipulation and analysis of sequences of characters, are essential in addressing a wide spectrum of problems in computer science. Within this domain, string algorithms prove instrumental in tasks such as pattern matching, substring search, and the optimization of various string-related operations. + +As we explore, we'll know much about fundamental string algorithms, examining techniques like string matching, regular expressions, and dynamic programming. Join this journey into the heart of string manipulation, where the algorithms we encounter will become indispensable tools for deciphering, analyzing, and extracting valuable information from the world of characters and text. + +One of the case in string algorithms is Shuffle String. + +## Shuffle String + +Shuffling a string based on a given set of indices is a common algorithmic task. This process involves rearranging the characters of a string according to a specified order provided by a list of indices.The algorithm efficiently shuffles the characters of a string according to the specified indices, providing a versatile solution for scenarios where a custom order of characters is required. It is a linear-time algorithm, making it suitable for practical use cases with moderate-sized strings. + +## Python Code + +```python +# Define a function named shuffle_string that takes a string and a list of indices as input +def shuffle_string(string, indices): + # Get the length of the input string + n = len(string) + + # Create a list of n empty spaces + result = [" "] * n + + # Iterate through the indices and assign characters from the input string to the corresponding positions + for index in range(n): + result[indices[index]] = string[index] + + # Convert the list of characters back to a string and return the result + return "".join(result) + +# Check if the script is being run as the main program +if __name__ == "__main__": + # Prompt the user to enter a custom string + custom_string = input() + + # Prompt the user to enter a list of indices separated by space, convert them to integers, and store in a list + custom_indices = list(map(int, input().split())) + + # Prompt the user to enter the expected output after shuffling the string + expected_output = input() + + # Call the shuffle_string function with the custom string and indices + custom_output = shuffle_string(custom_string, custom_indices) + + # Print the result of the custom example + print(custom_output) + + # Check if the custom output matches the expected output and provide feedback + if custom_output == expected_output: + print("Test case passed.") + else: + print("Test case failed.") + +# Input: +# hello +# 4 1 3 2 0 +# oellh +# oellh +# Output: +# Test case passed. +``` + +### Step-by-Step Explanation + +1. **Function Definition (`shuffle_string`):** + - `shuffle_string` is a function that takes two parameters: `string` (the input string) and `indices` (a list of indices). + - It creates a list called `result` initialized with spaces, with the same length as the input string. + - It then iterates over the indices and assigns each character from the input string to the corresponding position in the `result` list. + - Finally, it joins the characters in the `result` list into a single string and returns that string. + + i. **Initialization of `result`:** + + ```python + pythonCopy code + result = [" "] * n + ``` + + - This line creates a list **`result`** containing **`n`** elements, each initialized with a space character (**`" "`**). + + ii. **Loop over Indices:** + + ```python + pythonCopy code + for index in range(n): + ``` + + - This line starts a **`for`** loop that iterates over the range of **`n`** (the length of the input string or indices list). + + iii. **Assign Characters to Result List:** + + ```python + pythonCopy code + result[indices[index]] = string[index] + ``` + + - Inside the loop, for each **`index`**, it assigns the character at the corresponding position in the **`string`** to the **`result`** list at the index specified by **`indices[index]`**. + - In other words, it shuffles the characters in the **`string`** to positions determined by the values in the **`indices`** list. + + iv. **Join Result List into a String:** + + ```python + pythonCopy code + return "".join(result) + ``` + + - After the loop completes, the function joins the characters in the **`result`** list into a single string. + - The **`"".join(result)`** expression concatenates all the characters in the **`result`** list without any separator, producing the final shuffled string. +2. **Main Section (`if name == "main":):** + - This block checks if the script is being run directly (not imported as a module). +3. **User Input for Custom Example:** + - It prompts the user to enter the input string and indices separated by spaces. The indices are converted to integers using `map` and `int`, and then converted to a list. +4. **Expected Output Input:** + - It prompts the user to enter the expected output for the custom example. +5. **Test the Custom Example:** + - It calls the `shuffle_string` function with the custom input and prints the result. +6. **Comparison and Printing Results:** + - It compares the actual output (`custom_output`) with the expected output. If they match, it prints "test case passed"; otherwise, it prints "test case failed." + +## C++ Code + +```cpp +#include +#include +#include + +// Function to shuffle the characters of a string based on provided indices +std::string shufflestring(const std::string& str, const std::vector& indices) +{ + int n = str.length(); + std::string result(n, ' '); // Initialize the result string with spaces + + // Iterate through the indices and assign characters from the input string to + // the corresponding positions + for (int index = 0; index < n; ++index) + { + result[indices[index]] = str[index]; + } + + return result; +} + +int main() +{ + // Custom Example + // std::cout << "Enter the string: "; + std::string customString; + std::getline(std::cin, customString); + + // std::cout << "Enter the indices separated by space: "; + std::string indicesInput; + std::getline(std::cin, indicesInput); + + std::istringstream iss(indicesInput); + std::vector customIndices; + + // Convert the space-separated string of indices to a vector of integers + int index; + while (iss >> index) + { + customIndices.push_back(index); + } + + // std::cout << "Enter the expected output: "; + std::string expectedOutput; + std::getline(std::cin, expectedOutput); + + // Call the shuffleString function with the custom string and indices + std::string customOutput = shufflestring(customString, customIndices); + std::cout << customOutput << std::endl; + + // Check if the custom output matches the expected output and provide feedback + if (customOutput == expectedOutput) + { + std::cout << "Test case passed." << std::endl; + } + else + { + std::cout << "Test case failed." << std::endl; + } + + return 0; +} + +// Input: +// hello +// 4 1 3 2 0 +// oellh +// oellh +// Output: +// Test case passed. +``` + +### Step-by-Step Explaination + +1. **Header Includes:** + - This includes the necessary C++ standard library headers for input/output and vector usage. +2. **Function Definition (`shuffleString`):** + + ```cpp + std::string shufflestring(const std::string& str, const std::vector& indices) { + ``` + + - This declares a function named `shufflestring` that takes a constant reference to a string (`str`) and a constant reference to a vector of integers (`indices`). + - The function returns a string. +3. **Variable Declarations:** + + ```cpp + int n = str.length(); + std::vector result(n, ' '); + ``` + + - `n` stores the length of the input string. + - `result` is a vector of characters initialized with `n` spaces. +4. **Loop Over Indices:** + + ```cpp + for (int index = 0; index < n; ++index) { + result[indices[index]] = str[index]; + } + ``` + + - This loop iterates over each index in the range [0, n). + - For each index, it assigns the character at the corresponding position in the `str` to the `result` vector at the index specified by `indices[index]`. + - Essentially, it shuffles the characters in the `str` to positions determined by the values in the `indices` vector. +5. **Return Shuffled String:** + + ```cpp + return result; + ``` + + - After the loop completes, the function returns a string created from the characters in the `result` vector using iterators. + +In the `main` function: + +```cpp +int main() +{ + // std::cout << "Enter the string: "; + std::string customString; + std::getline(std::cin, customString); +``` + + i. **User Input - String:** + +- The program prompts the user to enter a string. +- **`std::getline(std::cin, customString);`** reads the entire line of user input (including spaces) and stores it in the **`customString`** variable. + +```cpp + // std::cout << "Enter the indices separated by space: "; + std::string indicesInput; + std::getline(std::cin, indicesInput); +``` + + ii. **User Input - Indices:** + +- The program prompts the user to enter indices separated by space. +- **`std::getline(std::cin, indicesInput);`** reads the entire line of user input (including spaces) and stores it in the **`indicesInput`** variable. + +```cpp + std::istringstream iss(indicesInput); + std::vector customIndices; +``` + + iii. **String to Vector of Integers Conversion:** + +- An **`std::istringstream`** named **`iss`** is created using the input string **`indicesInput`**. This allows us to treat the string as an input stream for easy parsing. +- An empty vector of integers named **`customIndices`** is declared to store the converted indices. + +```cpp + int index; + while (iss >> index) + { + customIndices.push_back(index); + } +``` + + iv. **Parsing and Storing Indices:** + +- A **`while`** loop is used to parse the space-separated string of indices using the **`>>`** extraction operator from the **`iss`** stream. +- Each parsed integer is added to the **`customIndices`** vector using **`push_back`**. + + v. **Expected Output Input:** + +```cpp +// std::cout << "Enter the expected output: "; +std::string expectedOutput; +std::getline(std::cin, expectedOutput); +``` + +- Prompt the user to enter the expected output for the custom example. + + vi. **Test the Custom Example:** + +```cpp +std::string customOutput = shuffleString(customString, customIndices); +std::cout << customOutput << std::endl; +``` + +- Call the `shuffleString` function with the custom input and print the result. + + vii. **Comparison and Printing Results:** + +```cpp +if (customOutput == expectedOutput) { + std::cout << "Test case passed." << std::endl; +} else { + std::cout << "Test case failed." << std::endl; +} +``` + +- Compare the actual output (`customOutput`) with the expected output. Print whether the test case passed or failed. + +## Java Code + +```java +import java.util.Scanner; + +public class shufflestring { + + // Function to shuffle the characters of a string based on provided indices + public static String shuffleString(String str, int[] indices) { + int n = str.length(); + char[] result = new char[n]; + + // Iterate through the indices and assign characters from the input string to + // the corresponding positions + for (int index = 0; index < n; ++index) { + result[indices[index]] = str.charAt(index); + } + + // Convert the character array back to a string and return the result + return new String(result); + } + + public static void main(String[] args) { + try (Scanner scanner = new Scanner(System.in)) { + // Custom Example + // System.out.print("Enter the string: "); + String customString = scanner.nextLine(); + + // System.out.print("Enter the indices separated by space: "); + String[] indicesInput = scanner.nextLine().split(" "); + int[] customIndices = new int[indicesInput.length]; + + // Convert the array of strings to an array of integers + for (int i = 0; i < indicesInput.length; i++) { + customIndices[i] = Integer.parseInt(indicesInput[i]); + } + + // System.out.print("Enter the expected output: "); + String expectedOutput = scanner.nextLine(); + + // Call the shuffleString function with the custom string and indices + String customOutput = shuffleString(customString, customIndices); + System.out.println(customOutput); + + // Check if the custom output matches the expected output and provide feedback + if (customOutput.equals(expectedOutput)) { + System.out.println("Test case passed."); + } else { + System.out.println("Test case failed."); + } + } catch (NumberFormatException e) { + // Handle NumberFormatException if the user enters non-integer values for + // indices + e.printStackTrace(); + } + } +} + +// Input: +// hello +// 4 1 3 2 0 +// oellh +// oellh +// Output: +// Test case passed. +``` + +### Step-by-Step Explaination + +1. **Importing Libraries:** + - This line imports the **`Scanner`** class from the **`java.util`** package, which is used for user input. +2. **Class Declaration:** + + ```java + javaCopy code + public class shufflestring { + ``` + + - This declares a class named **`ShuffleString`**. +3. **Function Definition (`shuffleString`):** + + ```java + javaCopy code + public static String shuffleString(String str, int[] indices) { + int n = str.length(); + char[] result = new char[n]; + for (int index = 0; index < n; ++index) { + result[indices[index]] = str.charAt(index); + } + return new String(result); + } + ``` + + - This defines a static method **`shuffleString`** that takes a string **`str`** and an array of integers **`indices`** as parameters. + - It returns a string. + - Inside the function, it initializes a character array **`result`** of length **`n`** and iterates over the indices, rearranging characters based on the provided indices. +4. **Main Method:** + + ```python + public static void main(String[] args) + ``` + + - This is the main method where the program execution starts. +5. **User Input for Custom Example:** + + ```java + javaCopy code + Scanner scanner = new Scanner(System.in); + + // Custom Example + // System.out.print("Enter the string: "); + String customString = scanner.nextLine(); + + // System.out.print("Enter the indices separated by space: "); + String[] indicesInput = scanner.nextLine().split(" "); + int[] customIndices = new int[indicesInput.length]; + for (int i = 0; i < indicesInput.length; i++) { + customIndices[i] = Integer.parseInt(indicesInput[i]); + } + ``` + + - It creates a **`Scanner`** object for reading user input. + - It prompts the user to enter the string and indices separated by space. + - It then splits the entered indices into an array of strings and converts them to integers using a loop. +6. **Expected Output Input:** + + ```java + javaCopy code + // System.out.print("Enter the expected output: "); + String expectedOutput = scanner.nextLine(); + ``` + + - It prompts the user to enter the expected output for the custom example. +7. **Test the Custom Example:** + + ```java + javaCopy code + String customOutput = shuffleString(customString, customIndices); + System.out.println(customOutput); + ``` + + - It calls the **`shuffleString`** function with the custom input and prints the result. +8. **Comparison and Printing Results:** + + ```java + javaCopy code + // Test the custom example against the expected output + if (customOutput.equals(expectedOutput)) { + System.out.println("Test case passed."); + } else { + System.out.println("Test case failed."); + } + ``` + + - It compares the actual output (**`customOutput`**) with the expected output. If they match, it prints "Test case passed"; otherwise, it prints "Test case failed." +9. **Closing Scanner and Class Closing Brace:** + - It's good practice to close the **`Scanner`** to prevent resource leaks. + - The closing brace **`}`** marks the end of the class. + + ## Time and Space Complexity Analysis + + ### Time Complexity : + + - The primary operation inside the function is the loop that iterates over the length of the input string, which is **`n`**. + - The loop has a constant time operation inside it (assignment and character retrieval). + - Therefore, the time complexity of the code is O(n), where 'n' is the length of the input string. + + ### Space Complexity : + + - The space complexity is determined by the additional space used by the algorithm. + - The primary data structure consuming space is the **`result`** array of characters, which has a length of 'n' (the length of the input string). + - Additionally, there are constant space requirements for variables like **`index`**. + - Therefore, the space complexity is O(n), where 'n' is the length of the input string. + + ## Real world Applications + + The code shuffle string shuffles a string based on given indices. While the specific use case may seem simplistic, this type of operation is foundational in various real-world applications. Here are a few examples: + + 1. **Encryption Algorithms:** + - Shuffling characters based on a specific pattern or key is a fundamental operation in some encryption algorithms. For example, a simple substitution cipher may involve rearranging characters in a string according to a predefined rule. + 2. **Data Security:** + - In security-related applications, shuffling data can be part of obfuscation techniques. It makes it more difficult for unauthorized users to understand the structure or patterns in the data, adding a layer of security. + 3. **Data Transmission:** + - In communication protocols, especially error-correction and channel coding, shuffling bits or symbols can help in ensuring that errors are spread out and not concentrated in one area. This aids in the recovery of corrupted data. + 4. **Password Hashing:** + - Password hashing algorithms often involve shuffling characters or bits to generate a unique hash for a given password. This adds complexity to the hashing process and enhances security. + 5. **Randomization in Games:** + - Shuffling elements is a common operation in games, especially card games. The provided code could be adapted to shuffle a deck of cards in a card game simulation. + 6. **Image Processing:** + - In image processing, shuffling pixel values based on certain criteria can be used for various effects or transformations. This could include scrambling parts of an image for privacy or generating artistic effects. + 7. **Genetic Algorithms:** + - Genetic algorithms involve evolving solutions based on the principles of natural selection. Shuffling genetic information (chromosomes) is a common operation to introduce diversity in the population and explore different solutions. + 8. **Cryptographic Applications:** + - Shuffling bits or bytes is used in some cryptographic techniques, such as in the creation of pseudorandom numbers or in stream ciphers. + 9. **Network Routing:** + - In networking, shuffling can be used in certain routing algorithms to distribute traffic across different paths, optimizing the usage of network resources. + 10. **Code Obfuscation:** + - Shuffling code instructions or altering the order of statements can be a form of code obfuscation, making it more challenging for reverse engineers to understand the logic of a program. + +## Test Cases +- Input: + + Custom string: "hello" + Custom indices: 4 1 3 2 0 + Expected output: "oellh" + + Output Explanation: + - The input string is "hello" and the list of indices is [4, 1, 3, 2, 0]. + - The function shuffle_string shuffles the characters of the input string based on the provided indices. Each character of the input string is assigned to the position specified by the corresponding index. + - The character at index 0 of the input string ("h") is assigned to position 4 in the result. + - The character at index 1 of the input string ("e") is assigned to position 1 in the result. + - The character at index 2 of the input string ("l") is assigned to position 3 in the result. + - The character at index 3 of the input string ("l") is assigned to position 2 in the result. + - The character at index 4 of the input string ("o") is assigned to position 0 in the result. + - After shuffling, the resulting string is "oellh". + - The function returns this shuffled string as the output. + + Output: + Shuffled string: "oellh" + Test case passed. + + The function successfully shuffles the characters of the input string according to the provided indices, resulting in the output "oellh", which matches the expected output. Therefore, the test case is passed. + +- Input: + + Custom string: "ABC" + Custom indices: 2 1 0 + Expected output: "cba" + + Output Explanation: + - The input string is "abc" and the list of indices is [2, 1, 0]. + - The function shuffle_string shuffles the characters of the input string based on the provided indices. Each character of the input string is assigned to the position specified by the corresponding index. + - The character at index 0 of the input string ("a") is assigned to position 2 in the result. + - The character at index 1 of the input string ("b") is assigned to position 1 in the result. + - The character at index 2 of the input string ("c") is assigned to position 0 in the result. + - After shuffling, the resulting string is "cba". + - The function returns this shuffled string as the output. + + Output: + Shuffled string: "cba" + Test case passed. + + The function successfully shuffles the characters of the input string according to the provided indices, resulting in the output "cba", which matches the expected output. Therefore, the test case is passed. diff --git a/Strings/Medium/Shuffle String/shufflestring.cpp b/Strings/Medium/Shuffle String/shufflestring.cpp new file mode 100644 index 00000000..bdfb1294 --- /dev/null +++ b/Strings/Medium/Shuffle String/shufflestring.cpp @@ -0,0 +1,67 @@ +#include +#include +#include + +// Function to shuffle the characters of a string based on provided indices +std::string shuffleString(const std::string &str, const std::vector &indices) +{ + int n = str.length(); + std::string result(n, ' '); // Initialize the result string with spaces + + // Iterate through the indices and assign characters from the input string to + // the corresponding positions + for (int index = 0; index < n; ++index) + { + result[indices[index]] = str[index]; + } + + return result; +} + +int main() +{ + // Custom Example + std::cout << "Enter the string: "; + std::string customString; + std::getline(std::cin, customString); + + std::cout << "Enter the indices separated by space: "; + std::string indicesInput; + std::getline(std::cin, indicesInput); + + std::istringstream iss(indicesInput); + std::vector customIndices; + + // Convert the space-separated string of indices to a vector of integers + int index; + while (iss >> index) + { + customIndices.push_back(index); + } + + std::cout << "Enter the expected output: "; + std::string expectedOutput; + std::getline(std::cin, expectedOutput); + + // Call the shuffleString function with the custom string and indices + std::string customOutput = shuffleString(customString, customIndices); + std::cout << "Custom Example Result: " << customOutput << std::endl; + + // Check if the custom output matches the expected output and provide feedback + if (customOutput == expectedOutput) + { + std::cout << "Test case passed." << std::endl; + } + else + { + std::cout << "Test case failed." << std::endl; + } + + return 0; +} + +// Enter the string: hello +// Enter the indices separated by space: 4 1 3 2 0 +// Enter the expected output: oellh +// Custom Example Result: oellh +// Test case passed. \ No newline at end of file diff --git a/Strings/Medium/Shuffle String/shufflestring.java b/Strings/Medium/Shuffle String/shufflestring.java new file mode 100644 index 00000000..8578e947 --- /dev/null +++ b/Strings/Medium/Shuffle String/shufflestring.java @@ -0,0 +1,60 @@ +import java.util.Scanner; + +public class shufflestring { + + // Function to shuffle the characters of a string based on provided indices + public static String shuffleString(String str, int[] indices) { + int n = str.length(); + char[] result = new char[n]; + + // Iterate through the indices and assign characters from the input string to + // the corresponding positions + for (int index = 0; index < n; ++index) { + result[indices[index]] = str.charAt(index); + } + + // Convert the character array back to a string and return the result + return new String(result); + } + + public static void main(String[] args) { + try (Scanner scanner = new Scanner(System.in)) { + // Custom Example + System.out.print("Enter the string: "); + String customString = scanner.nextLine(); + + System.out.print("Enter the indices separated by space: "); + String[] indicesInput = scanner.nextLine().split(" "); + int[] customIndices = new int[indicesInput.length]; + + // Convert the array of strings to an array of integers + for (int i = 0; i < indicesInput.length; i++) { + customIndices[i] = Integer.parseInt(indicesInput[i]); + } + + System.out.print("Enter the expected output: "); + String expectedOutput = scanner.nextLine(); + + // Call the shuffleString function with the custom string and indices + String customOutput = shuffleString(customString, customIndices); + System.out.println("Custom Example Result: " + customOutput); + + // Check if the custom output matches the expected output and provide feedback + if (customOutput.equals(expectedOutput)) { + System.out.println("Test case passed."); + } else { + System.out.println("Test case failed."); + } + } catch (NumberFormatException e) { + // Handle NumberFormatException if the user enters non-integer values for + // indices + e.printStackTrace(); + } + } +} + +// Enter the string: hello +// Enter the indices separated by space: 4 1 3 2 0 +// Enter the expected output: oellh +// Custom Example Result: oellh +// Test case passed. \ No newline at end of file diff --git a/Strings/Medium/Shuffle String/shufflestring.py b/Strings/Medium/Shuffle String/shufflestring.py new file mode 100644 index 00000000..6422cc71 --- /dev/null +++ b/Strings/Medium/Shuffle String/shufflestring.py @@ -0,0 +1,44 @@ +# Define a function named shuffle_string that takes a string and a list of indices as input +def shuffle_string(string, indices): + # Get the length of the input string + n = len(string) + + # Create a list of n empty spaces + result = [" "] * n + + # Iterate through the indices and assign characters from the input string to the corresponding positions + for index in range(n): + result[indices[index]] = string[index] + + # Convert the list of characters back to a string and return the result + return "".join(result) + +# Check if the script is being run as the main program +if __name__ == "__main__": + # Prompt the user to enter a custom string + custom_string = input("Enter the string: ") + + # Prompt the user to enter a list of indices separated by space, convert them to integers, and store in a list + custom_indices = list(map(int, input("Enter the indices separated by space: ").split())) + + # Prompt the user to enter the expected output after shuffling the string + expected_output = input("Enter the expected output: ") + + # Call the shuffle_string function with the custom string and indices + custom_output = shuffle_string(custom_string, custom_indices) + + # Print the result of the custom example + print("Custom Example Result:", custom_output) + + # Check if the custom output matches the expected output and provide feedback + if custom_output == expected_output: + print("Test case passed.") + else: + print("Test case failed.") + + +# Enter the string: hello +# Enter the indices separated by space: 4 1 3 2 0 +# Enter the expected output: oellh +# Custom Example Result: oellh +# Test case passed. \ No newline at end of file