Practice Final 4 Solutions


Question 1: Melt

void melt(Lexicon& lex, string& a, string& b, string soFar, Set<string>& set)
{
    if (lex.contains(soFar))
    {
        set.add(soFar);
    }

    if (!lex.containsPrefix(soFar))
    {
        return;
    }

    if (!a.empty())
    {
        char thisOne = a[0];
        a = a.substr(1);

        melt(lex, a, b, soFar, set);
        melt(lex, a, b, soFar + thisOne, set);

        // Failure to add this back results in sadness.
        a = thisOne + a;
    }

    if (!b.empty())
    {
        char thisOne = b[0];
        b = b.substr(1);

        melt(lex, a, b, soFar, set);
        melt(lex, a, b, soFar + thisOne, set);

        // Failure to add this back results in sadness.
        b = thisOne + b;
    }
}

Set<string> melt(string a, string b)
{
    Lexicon lex("EnglishWords.txt");
    Set<string> set;
    melt(lex, a, b, "", set);
    return set;
}


Question 2: Graph Class

Graph::Graph(Grid<bool> matrix) {
    _matrix = matrix;
    _numNodes = matrix.numCols();
    _numEdges = 0;

    // Notice that the inner loop does not start
    // with j = 0. See note about this below.
    for (int i = 0; i < _numNodes; i++) {
        for (int j = i; j < _numNodes; j++) {
            if (_matrix[i][j]) {
                _numEdges++;
            }
        }
    }

    // Note: Because of self-loops, counting up ALL
    // edges in the graph and then dividing by two
    // does not work!
}

Graph::~Graph() {
}

void Graph::checkValid(int n1) const {
    if (n1 < 0 || n1 >= _numNodes) {
        error("Invalid index!");
    }
}

void Graph::addEdge(int n1, int n2) {
    checkValid(n1);
    checkValid(n2);
    if (!_matrix[n1][n2]) {
        _matrix[n1][n2] = _matrix[n2][n1] = true;
        _numEdges++;
    }
}

void Graph::removeEdge(int n1, int n2) {
    checkValid(n1);
    checkValid(n2);
    if (_matrix[n1][n2]) {
        _matrix[n1][n2] = _matrix[n2][n1] = false;
        _numEdges--;
    }
}

bool Graph::edge(int n1, int n2) const {
    checkValid(n1);
    checkValid(n2);
    return _matrix[n1][n2];
}

Set<int> Graph::neighbors(int n1) const {
    checkValid(n1);
    Set<int> set;
    for (int i = 0; i < _numNodes; i++) {
        if (_matrix[n1][i]) {
            set.add(i);
        }
    }
    return set;
}

int Graph::nodeCount() const {
    return _numNodes;
}

int Graph::edgeCount() const {
    return _numEdges;
}


Question 3: Ping

bool ping(Node*& head, int value)
{
    // Find value;
    Node *current = head;
    while (current != nullptr && current->data != value)
    {
        current = current->next;
    }

    // Not found.
    if (current == nullptr) {
        return false;
    }

    // Found! Increment.
    current->pCnt++;

    // First of all, if nothing to do, just leave function.
    if (current->prev == nullptr || current->prev->pCnt >= current->pCnt) {
        return true;
    }

    // Otherwise, work backward to find where target node should be injected.
    Node *insertBefore = current->prev;
    while (insertBefore->prev != nullptr && insertBefore->prev->pCnt < current->pCnt)
    {
        insertBefore = insertBefore->prev;
    }

    // Remove node from list. We know current->prev is not null, so this is safe.
    current->prev->next = current->next;
    // However, its next pointer could be null, so be careful here.
    if (current->next != nullptr) {
        current->next->prev = current->prev;
    }

    // Now wire node into new position.
    current->next = insertBefore;
    current->prev = insertBefore->prev;

    insertBefore->prev = current;
    // Guard against segfault in event that the target node has become head.
    if (current->prev != nullptr) {
        current->prev->next = current;
    }

    // If the target node has nothing before it, it's the new head of the list!
    if (current->prev == nullptr) {
        head = current;
    }

    return true;
}


Question 4: Threshold Sum

int threshSum(TreeNode* root, int threshold) {
    if (root == nullptr) {
        return 0;
    }
    if (root->left == nullptr && root->right == nullptr) {
        if (root->data >= threshold) {
            return root->data;
        }
        return 0;
    }

    // If root->data < threshold, then everything in its left subtree is
    // < threshold as well, since this is a BST -- so it would be wasteful to
    // go into the leftsubtree in that case.
    if (root->data < threshold) {
        return threshSum(root->right, threshold);
    } else {
        return threshSum(root->left, threshold) + threshSum(root->right, threshold);
    }
}

Question 5a: BFS

  • RAINSBLOUD: No

  • DOUNBIRELSA: Yes

  • DOUBLERANIS: No

  • BOLDUENRIAS: No

  • DOUNBELRAIS: No

Question 5b: Topological Sort

  • BADEC: No

  • ABCDE: No

  • BACDE: No

  • ADCBE: Yes

  • ADBCE: Yes

Question 6: Find Exit

bool findExit(Cell *current, Cell*& goal, HashSet<Cell*>& set)
{
    if (current == nullptr)
    {
        return false;
    }

    if (set.contains(current)) {
        return false;
    }
    set.add(current);

    if (current->content == "exit")
    {
        goal = current;
        return true;
    }
    else if (findExit(current->up, goal, set))
    {
        return true;
    }
    else if (findExit(current->down, goal, set))
    {
        return true;
    }
    else if (findExit(current->left, goal, set))
    {
        return true;
    }
    else if (findExit(current->right, goal, set))
    {
        return true;
    }
    else
    {
        return false;
    }
}

Cell* findExit(Cell *start)
{
    Cell *goal = nullptr;
    HashSet<Cell*> set;
    findExit(start, goal, set);
    return goal;
}