-
Notifications
You must be signed in to change notification settings - Fork 23
Alien dictionary (additional task) #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 20 commits
f0bd3c8
1d846ff
d3602f6
22ffad7
3709d12
e3e497c
75d57fa
fa8ba68
f13ca9f
2964511
5ae7967
bbf95ff
9c125dd
f336d1a
c8bafd0
7e7f127
c39126d
fa06373
b839a46
89c7dbe
22d5ff8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Alien dictionary | ||
|
||
Given a sorted dictionary (array of words) of an alien language, find the order of characters in the language. | ||
For example, given the following dictionary: | ||
### {"hl", "ld", "wd", "dd"} | ||
|
||
The order of characters in the alien language is: | ||
### "hlwd" | ||
|
||
## P.S. The order of the characters must be unambiguously defined with the words in the dictionary. | ||
If not, the program will determine the character order, which can be determined by the word order in the dictionary, but this character order may not be the only possible one. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#include "utils.hpp" | ||
|
||
int main() { | ||
std::vector<std::string> dictionary = {"baa", "abcd", "abca", "cab", "cad"}; | ||
FindAlphabeticOrder(dictionary); | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,61 @@ | ||||||||||||||||||
#include <gtest/gtest.h> | ||||||||||||||||||
|
||||||||||||||||||
#include <sstream> | ||||||||||||||||||
#include <string> | ||||||||||||||||||
#include <vector> | ||||||||||||||||||
|
||||||||||||||||||
#include "utils.hpp" | ||||||||||||||||||
|
||||||||||||||||||
// Helper function to capture the output of FindAlphabeticOrder | ||||||||||||||||||
std::string CaptureOutput(const std::vector<std::string>& dictionary) { | ||||||||||||||||||
std::ostringstream output; | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]
Suggested change
|
||||||||||||||||||
std::streambuf* oldCoutBuffer = | ||||||||||||||||||
std::cout.rdbuf(output.rdbuf()); // Redirect cout to output stream | ||||||||||||||||||
|
||||||||||||||||||
FindAlphabeticOrder(dictionary); // Call the function | ||||||||||||||||||
|
||||||||||||||||||
std::cout.rdbuf(oldCoutBuffer); // Restore cout | ||||||||||||||||||
return output.str(); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
TEST(AlienDictionaryTests, SimpleTest) { | ||||||||||||||||||
std::vector<std::string> dictionary = {"hl", "ld", "wd", "dd"}; | ||||||||||||||||||
std::string output = CaptureOutput(dictionary); | ||||||||||||||||||
ASSERT_EQ(output, "hlwd\n"); // Expected order | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
TEST(AlienDictionaryTests, BasicOrderTest) { | ||||||||||||||||||
std::vector<std::string> dictionary = {"baa", "abcd", "abca", "cab", "cad"}; | ||||||||||||||||||
std::string output = CaptureOutput(dictionary); | ||||||||||||||||||
ASSERT_EQ(output, "bdac\n"); // Expected order | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
TEST(AlienDictionaryTests, NoOrderTest) { | ||||||||||||||||||
std::vector<std::string> dictionary = {"abc", "bca", "bac", "cab"}; | ||||||||||||||||||
std::string output = CaptureOutput(dictionary); | ||||||||||||||||||
ASSERT_EQ(output, | ||||||||||||||||||
"The graph contains a cycle. Topological sorting is not " | ||||||||||||||||||
"determined.\n"); // Cycle detected | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
TEST(AlienDictionaryTests, SingleWordTest) { | ||||||||||||||||||
std::vector<std::string> dictionary = {"a"}; | ||||||||||||||||||
std::string output = CaptureOutput(dictionary); | ||||||||||||||||||
ASSERT_EQ(output, "a\n"); // Only one character | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
TEST(AlienDictionaryTests, EmptyDictionaryTest) { | ||||||||||||||||||
std::vector<std::string> dictionary = {}; | ||||||||||||||||||
std::string output = CaptureOutput(dictionary); | ||||||||||||||||||
ASSERT_EQ(output, ""); // No output for empty dictionary | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
TEST(AlienDictionaryTests, ComplexOrderTest) { | ||||||||||||||||||
// Updated dictionary to test a different order | ||||||||||||||||||
std::vector<std::string> dictionary = {"aaa", "abb", "bat", "bar", | ||||||||||||||||||
"cab", "cat", "tar", "rat"}; | ||||||||||||||||||
|
||||||||||||||||||
// Updated expected output based on the new dictionary | ||||||||||||||||||
std::string output = CaptureOutput(dictionary); | ||||||||||||||||||
ASSERT_EQ(output, "abctr\n"); // Check for possible valid orders | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#include "utils.hpp" | ||
|
||
void ForceAddDirEdge(Graph<char>& graph, char u, char v) { | ||
// Add vertices if they do not exist | ||
if (graph.Size() == 0 || graph.Find(u) == graph.Size()) { | ||
graph.AddVertex(u); | ||
} | ||
if (graph.Find(v) == graph.Size()) { | ||
graph.AddVertex(v); | ||
} | ||
// Add directed edge from u to v | ||
graph.AddDirEdge(graph.Find(u), graph.Find(v)); | ||
} | ||
|
||
bool TopologicalSortStep(Graph<char>& graph, size_t v, std::set<char>& visited, | ||
std::set<char>& recursion, std::stack<char>& stack) { | ||
// Mark the current node as visited and add it to the recursion stack | ||
visited.insert(graph[v]->data); | ||
recursion.insert(graph[v]->data); | ||
|
||
// Recur for all the vertices adjacent to this vertex | ||
for (const auto& neighbor : graph[v]->adjacent) { | ||
if (recursion.find(neighbor->data) != recursion.end()) { | ||
// If the neighbor is in the recursion stack, we found a cycle | ||
return true; | ||
} | ||
if (visited.find(neighbor->data) == visited.end()) { | ||
if (TopologicalSortStep(graph, graph.Find(neighbor->data), visited, | ||
recursion, stack)) { | ||
return true; // Cycle detected in the recursive call | ||
} | ||
} | ||
} | ||
|
||
// Remove the vertex from recursion and add it to the result | ||
recursion.erase(graph[v]->data); | ||
stack.push(graph[v]->data); | ||
return false; // No cycle detected | ||
} | ||
|
||
void FindAlphabeticOrder(const std::vector<std::string>& words) { | ||
if (words.empty()) return; // No words to sort | ||
|
||
// Only one word, thus it contains the only character | ||
if (words.size() == 1) { | ||
std::cout << words[0] << std::endl; | ||
return; | ||
} | ||
|
||
Graph<char> graph; | ||
|
||
// Build the graph by iterating through adjacent words | ||
for (size_t i = 0; i < words.size() - 1; ++i) { | ||
std::string curr_word = words[i]; | ||
std::string next_word = words[i + 1]; | ||
size_t minLength = std::min(curr_word.length(), next_word.length()); | ||
|
||
for (size_t j = 0; j < minLength; ++j) { | ||
if (curr_word[j] != next_word[j]) { | ||
ForceAddDirEdge(graph, curr_word[j], next_word[j]); | ||
break; // Only the first different character matters | ||
} | ||
} | ||
} | ||
|
||
// Perform topological sorting and check for cycles | ||
std::set<char> visited; | ||
std::set<char> recursion; // To keep track of the recursion | ||
std::stack<char> result; | ||
|
||
for (size_t i = 0; i < graph.Size(); ++i) { | ||
if (visited.find(graph[i]->data) == visited.end()) { | ||
if (TopologicalSortStep(graph, i, visited, recursion, result)) { | ||
std::cout << "The graph contains a cycle. Topological sorting is not " | ||
"determined." | ||
<< std::endl; | ||
return; // Cycle detected | ||
} | ||
} | ||
} | ||
|
||
// Print the characters in reverse order | ||
while (!result.empty()) { | ||
std::cout << result.top(); | ||
result.pop(); | ||
} | ||
std::cout << std::endl; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#pragma once | ||
|
||
#include <stack> | ||
|
||
#include "graph.hpp" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. warning: 'graph.hpp' file not found [clang-diagnostic-error] #include "graph.hpp"
^ |
||
|
||
// Adds a directed edge between characters u and v | ||
// Processes if this is the first occurrence for any of the characters | ||
void ForceAddDirEdge(Graph<char>& graph, char u, char v); | ||
|
||
// DFS, performing topological sort and detecting cycles | ||
bool TopologicalSortStep(Graph<char>& graph, size_t v, std::set<char>& visited, | ||
std::set<char>& recursion, std::stack<char>& stack); | ||
|
||
// Function to process the words and find the character order | ||
void FindAlphabeticOrder(const std::vector<std::string>& dictionary); |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: variable 'output' of type 'std::ostringstream' (aka 'basic_ostringstream') can be declared 'const' [misc-const-correctness]