Friday, 27 November 2015

Insertion Sort - Find the Number of Larger Values in the Remaining Array

1. Problem Description
This is a Google interview question from careercup. Here is the original thread,

- PradeepN about a month ago in United States | Report Duplicate | Flag ".

2. Pseudo-code
The idea is to start from the right hand side of array to the left hand side and use insertion sort.
    - Initialize a sorted data like std::set as sortedArray
    - Initialize a linked list to take the result, result
    - Take the element, x, from the array in the reverse order
    - Find the number of larger value in sortedArray than x, as n
    - Push n into the front of result
    - Insert x into sortedArray
    - Loop the above 4 steps until exhaust the whole array
    - Return result

As the loop goes on, each element is inserted into a sorted array. This is good hint to employ insertion sort. But normally insertion sort uses continuous memory array, then it requires linear memory shift. Therefore the key is to use node-based data structure like binary tree in this case. Again the result is populated in the reverse order. Therefore a linked-list is good option to take the result because it take constant time to push a value in the front.

Alternative approach:
    - Sort the array by a binary tree, sortedArray
    - Initialize a vector to take result, result
    - Take the element, x, in the left-to-right order
    - Find the number of larger value than x in sortedArray, as n
    - Push back n into result
    - Remove x from sortedArray
    - Repeat the above 4 steps until exhaust the whole array
    - Return result

3. C++ Implementation
// ********************************************************************************
// Implementation
// ********************************************************************************
#include <set>
#include <list>
#include <vector>

template <typename T>
std::vector<T> FindTheNumberOfLargerValuesInTheRemainingArray(std::vector<T> const& input)
{
    std::set<T> sortedArray;
    std::list<T> result;
    auto iterEnd = input.rend();
    for (auto iter = input.rbegin(); iter != iterEnd; ++iter) {
        auto ub = sortedArray.upper_bound(*iter);
        result.push_front(std::distance(ub, sortedArray.end()));
        sortedArray.insert(*iter);
    }

    return std::vector<T>(result.begin(), result.end());
}

// ********************************************************************************
// Test
// ********************************************************************************
#include <cassert>
void TestFindTheNumberOfLargerValuesInTheRemainingArray()
{
    {
        std::vector<int> input;
        std::vector<int> output = FindTheNumberOfLargerValuesInTheRemainingArray(input);
        assert(output.empty() == true);

        input.push_back(0);
        output = FindTheNumberOfLargerValuesInTheRemainingArray(input);
        assert(output.size() == 1);
        assert(output[0] == 0);
    }

    {
        std::vector<int> input = { 3, 4, 5, 9, 2, 1, 3 };
        const std::vector<int> result = { 3, 2, 1, 0, 1, 1, 0 };
        std::vector<int> output = FindTheNumberOfLargerValuesInTheRemainingArray(input);
        assert(result == output);
    }

    {
        std::vector<int> input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        const std::vector<int> result = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
        std::vector<int> output = FindTheNumberOfLargerValuesInTheRemainingArray(input);
        assert(result == output);
    }

    {
        std::vector<int> input = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
        const std::vector<int> result = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        std::vector<int> output = FindTheNumberOfLargerValuesInTheRemainingArray(input);
        assert(result == output);
    }
}

Saturday, 14 November 2015

Trie - Live Stream Words Detector

1. Problem Description
"
".

2. Algorithm
The idea is to use Trie structure to build up the dictionary. Feed the live stream into the dictionary (assuming a new character is coming at a time). Go down deep into the tree (Trie data structure) one more level given the newly coming character. Keep a list of valid tree paths and go through the list when a new character is coming.
    - Generate signal to call the API, if a new word is found with the new character.
      Keep this tree path because following character(s) can form new words.
    - Keep this tree path in the list, if does not find a new word but the tree path is valid.
      Because it is one of candidates to form a new word with the following stream.
    - Remove this tree path from the list, if the tree path is invalid.
    - Search the new character in the root of dictionary
        - Call the API and add the tree path into the list, if this single character is a word.
        - Add the tree path into the list, if the tree path is valid.

3. C++ Implementation
This implementation is based on my previous blog entry about Trie structure, Data Structure and Algorithm - Trie.
// ********************************************************************************
// Implementation
// ********************************************************************************
// Header 
#pragma once

#include <list>
#include <string>
#include <vector>

struct DictionaryTrie;

class LiveStreamWordsDetector
{
public:
    LiveStreamWordsDetector();
    LiveStreamWordsDetector(std::vector<std::string> const &words);
    ~LiveStreamWordsDetector();

    void AddWordIntoDict(std::string const& word);
    void AddWordsIntoDict(std::vector<std::string> const &words);

    void AppendLiveStream(char const ch,
                          std::vector<std::string> &liveWords);

private:
    DictionaryTrie* mDictRoot;
    std::list<DictionaryTrie*> mPossibleWords;
};

// CPP
#include "LiveStreamWordsDetector.h"

#include "DictionaryTrie.h"
#include "DictionaryTrie_internal.h"

LiveStreamWordsDetector::LiveStreamWordsDetector()
: mDictRoot(new DictionaryTrie())
{
}

LiveStreamWordsDetector::LiveStreamWordsDetector(std::vector<std::string> const &words)
: mDictRoot(new DictionaryTrie())
{
    AddWordsIntoDict(words);
}

LiveStreamWordsDetector::~LiveStreamWordsDetector()
{
    DestoryDictionaryTrie(mDictRoot);
    mDictRoot = nullptr;
}

void LiveStreamWordsDetector::AddWordIntoDict(std::string const &word)
{
    AddWord(mDictRoot, word.c_str());
}

void LiveStreamWordsDetector::AddWordsIntoDict(std::vector<std::string> const &words)
{
    auto iterEnd = words.end();
    for (auto iter = words.begin(); iter != iterEnd; ++iter) {
        AddWordIntoDict(*iter);
    }
}

void LiveStreamWordsDetector::AppendLiveStream(char const ch, std::vector<std::string> &words)
{
    words.clear();
    DictionaryTrie* temp = nullptr;
    //  check the previous valid words
    for (auto iter = mPossibleWords.begin(); iter != mPossibleWords.end();) {
        temp = LocateChar(*iter, ch);
        if (temp){
            // replace with the new pointer after appending the new character
            *iter = temp;
            if (temp->str) {
                // a word found
                words.push_back(temp->str);
            }
            ++iter;
        }
        else {
            // remove from the list if the appending char makes the word invalid
            iter = mPossibleWords.erase(iter);
        }
    }
    // add the new starting character into list if exists
    temp = LocateChar(mDictRoot, ch);
    if (temp) {
        mPossibleWords.push_front(temp);
        if (temp->str) {
            // a word found - single character word
            words.push_back(&ch);
        }
    }
}

// ********************************************************************************
// Test
// ********************************************************************************
void TestLiveStream()
{
    const std::vector<std::string> words =
        {"ok", "test", "one", "try", "trying"};
    LiveStreamWordsDetector lsd(words);

    const std::string input("abcokdeftrying");
    std::vector<std::string> output;

    lsd.AppendLiveStream('a', output);
    assert(output.empty());
    lsd.AppendLiveStream('b', output);
    assert(output.empty());
    lsd.AppendLiveStream('c', output);
    assert(output.empty());
    lsd.AppendLiveStream('o', output);
    assert(output.empty());
    lsd.AppendLiveStream('k', output);
    assert(output.size() == 1);
    assert(output[0] == "ok");

    lsd.AppendLiveStream('d', output);
    assert(output.empty());
    lsd.AppendLiveStream('e', output);
    assert(output.empty());
    lsd.AppendLiveStream('f', output);
    assert(output.empty());
    lsd.AppendLiveStream('t', output);
    assert(output.empty());
    lsd.AppendLiveStream('r', output);
    assert(output.empty());
    lsd.AppendLiveStream('y', output);
    assert(output.size() == 1);
    assert(output[0] == "try");
    lsd.AppendLiveStream('i', output);
    assert(output.empty());
    lsd.AppendLiveStream('n', output);
    assert(output.empty());
    lsd.AppendLiveStream('g', output);
    assert(output.size() == 1);
    assert(output[0] == "trying");
}

Sunday, 1 November 2015

LinkedList - Split Linked List into Fibonacci and Non-Fibonacci Lists (Amazon Interview Question)

1. Problem Description

- a.ahmed.shalabey 6 days ago in United States for Software Development | Report Duplicate | Flag ".

2. Implementation
The idea is quite simple that check each element if it is a Fibonacci number. If yes, append the Fibonacci number into one list otherwise append the number into another list.

In this implementation the newly introduced feature "std::function" is used to pass a predicate (a function that take the template type as the argument and return bool) as the parameter. And implement a predicate to tell if an number is Fibonacci number, which is passed into the linked-list split function. Literally this implementation can take any predicate to split the linked list into two parts, not necessarily only Fibonacci and non-Fibonacci. 

// ********************************************************************************
// Implementation
// ********************************************************************************
#include <functional>

template <typename T>
void LL_SpiltLinkedList(LinkedListElement<T>** input,
                        LinkedListElement<T>** splitOnTrue,
                        LinkedListElement<T>** splitOnFalse,
                        std::function<bool (const T&)> func)
{
    if (input == nullptr || *input == nullptr) {
        return;
    }

    LinkedListElement<T>* curNode = *input;
    LinkedListElement<T>* nodesOnTrue = nullptr;
    LinkedListElement<T>* nodesOnFalse = nullptr;
    while (curNode) {
        if (func(curNode->data)) {
            if (*splitOnTrue == nullptr) {
                *splitOnTrue = curNode;
                nodesOnTrue = *splitOnTrue;
            }
            else {
                nodesOnTrue->next = curNode;
                nodesOnTrue = nodesOnTrue->next;
            }
        }
        else {
            if (*splitOnFalse == nullptr) {
                *splitOnFalse = curNode;
                nodesOnFalse = *splitOnFalse;
            }
            else {
                nodesOnFalse->next = curNode;
                nodesOnFalse = nodesOnFalse->next;
            }
        }
        curNode = curNode->next;
    }
    if (nodesOnTrue) {
        nodesOnTrue->next = nullptr;
    }
    if (nodesOnFalse) {
        nodesOnFalse->next = nullptr;
    }
    *input = nullptr;
}

bool IsFibonaciNumber(int val)
{
    int temp = 5 * val*val;
    int root = static_cast<int>(sqrt(temp - 4));
    if (root*root == (temp - 4)) {
        return true;
    }

    root = static_cast<int>(sqrt(temp + 4));
    if (root*root == (temp + 4)) {
        return true;
    }

    return false;
}

// ********************************************************************************
// Test
// ********************************************************************************
void TestSplitLLAgainstFibonaci()
{
    {
        LinkedListElement<int>* head = nullptr;
        LinkedListElement<int>* fibonaciNodes = nullptr;
        LinkedListElement<int>* nonFibonaciNodes = nullptr;
        LL_SpiltLinkedList<int>(&head, &fibonaciNodes, &nonFibonaciNodes, IsFibonaciNumber);

        assert(fibonaciNodes == nullptr);
        assert(nonFibonaciNodes == nullptr);
    }

    {
        std::vector<int> testArr = { 0, 1, 1, 2, 3, 5, 8 };

        LinkedListElement<int>* head = nullptr;
        LL_PushFrontFromStdVector(&head, testArr);

        LinkedListElement<int>* fibonaciNodes = nullptr;
        LinkedListElement<int>* nonFibonaciNodes = nullptr;
        LL_SpiltLinkedList<int>(&head, &fibonaciNodes, &nonFibonaciNodes, IsFibonaciNumber);

        assert(fibonaciNodes != nullptr);
        assert(nonFibonaciNodes == nullptr);
        assert(head == nullptr);

        std::vector<int> result;
        LL_CopyDataToStdVector(fibonaciNodes, result);
        assert(testArr == result);

        LL_Delete(&fibonaciNodes);
    }

    {
        std::vector<int> testArr = { 4, 6, 7, 9, 10 };

        LinkedListElement<int>* head = nullptr;
        LL_PushFrontFromStdVector(&head, testArr);

        LinkedListElement<int>* fibonaciNodes = nullptr;
        LinkedListElement<int>* nonFibonaciNodes = nullptr;
        LL_SpiltLinkedList<int>(&head, &fibonaciNodes, &nonFibonaciNodes, IsFibonaciNumber);

        assert(fibonaciNodes == nullptr);
        assert(nonFibonaciNodes != nullptr);
        assert(head == nullptr);

        std::vector<int> result;
        LL_CopyDataToStdVector(nonFibonaciNodes, result);
        assert(testArr == result);

        LL_Delete(&nonFibonaciNodes);
    }

    {
        std::vector<int> testArr = { 0, 4, 1, 6, 1, 7, 2, 9, 3, 10, 5, 8 };
        std::vector<int> fibonaciArr = { 0, 1, 1, 2, 3, 5, 8 };
        std::vector<int> nonFibonaciArr = { 4, 6, 7, 9, 10 };

        LinkedListElement<int>* head = nullptr;
        LL_PushFrontFromStdVector(&head, testArr);

        LinkedListElement<int>* fibonaciNodes = nullptr;
        LinkedListElement<int>* nonFibonaciNodes = nullptr;
        LL_SpiltLinkedList<int>(&head, &fibonaciNodes, &nonFibonaciNodes, IsFibonaciNumber);

        assert(fibonaciNodes != nullptr);
        assert(nonFibonaciNodes != nullptr);
        assert(head == nullptr);


        std::vector<int> fibonaciResult;
        LL_CopyDataToStdVector(fibonaciNodes, fibonaciResult);
        assert(fibonaciArr == fibonaciResult);

        std::vector<int> nonFibonaciResult;
        LL_CopyDataToStdVector(nonFibonaciNodes, nonFibonaciResult);
        assert(nonFibonaciArr == nonFibonaciResult);

        LL_Delete(&fibonaciNodes);
        LL_Delete(&nonFibonaciNodes);
    }
}