Skip to content

Instantly share code, notes, and snippets.

@xphoniex
Created January 6, 2019 19:48
Show Gist options
  • Save xphoniex/ec81075f42367c98e97e74726191fd8c to your computer and use it in GitHub Desktop.
Save xphoniex/ec81075f42367c98e97e74726191fd8c to your computer and use it in GitHub Desktop.
think-cell
/*
Task Description
interval_map<K,V> is a data structure that efficiently associates intervals of keys of type K with values of type V. Your task is to implement the assign member function of this data structure, which is outlined below.
interval_map<K, V> is implemented on top of std::map. In case you are not entirely sure which functions std::map provides, what they do and which guarantees they provide, we provide an excerpt of the C++ standard here:
Each key-value-pair (k,v) in the std::map means that the value v is associated with the interval from k (including) to the next key (excluding) in the std::map.
Example: the std::map (0,'A'), (3,'B'), (5,'A') represents the mapping
0 -> 'A'
1 -> 'A'
2 -> 'A'
3 -> 'B'
4 -> 'B'
5 -> 'A'
6 -> 'A'
7 -> 'A'
... all the way to numeric_limits<int>::max()
The representation in the std::map must be canonical, that is, consecutive map entries must not have the same value: ..., (0,'A'), (3,'A'), ... is not allowed. Initially, the whole range of K is associated with a given initial value, passed to the constructor of the interval_map<K,V> data structure.
Key type K
besides being copyable and assignable, is less-than comparable via operator<
is bounded below, with the lowest value being std::numeric_limits<K>::lowest()
does not implement any other operations, in particular no equality comparison or arithmetic operators
Value type V
besides being copyable and assignable, is equality-comparable via operator==
does not implement any other operations
*/
#include <map>
#include <limits>
#include <ctime>
template<typename K, typename V>
class interval_map {
std::map<K,V> m_map;
public:
// constructor associates whole range of K with val by inserting (K_min, val)
// into the map
interval_map( V const& val) {
m_map.insert(m_map.end(),std::make_pair(std::numeric_limits<K>::lowest(),val));
}
// Assign value val to interval [keyBegin, keyEnd).
// Overwrite previous values in this interval.
// Conforming to the C++ Standard Library conventions, the interval
// includes keyBegin, but excludes keyEnd.
// If !( keyBegin < keyEnd ), this designates an empty interval,
// and assign must do nothing.
void assign( K const& keyBegin, K const& keyEnd, V const& val ) {
if (!(keyBegin < keyEnd)) return;
std::pair<K,V> beginExtra;
std::pair<K,V> endExtra;
bool beginHasExtra = false;
bool endHasExtra = false;
typename std::map<K,V>::const_iterator itBegin;
itBegin = m_map.lower_bound(keyBegin);
if ( itBegin!=m_map.end() && keyBegin < itBegin->first ) {
if (itBegin != m_map.begin()) {
beginHasExtra = true;
--itBegin;
beginExtra = std::make_pair(itBegin->first, itBegin->second);
}
// openRange for erase is prevIterator
// insert (prevIterator->first, prevIterator->second) as well!
}
typename std::map<K,V>::const_iterator itEnd;
itEnd = m_map.lower_bound(keyEnd);
if ( itEnd!=m_map.end() && keyEnd < itEnd->first ) {
endHasExtra = true;
typename std::map<K,V>::const_iterator extraIt = itEnd;
--extraIt;
endExtra = std::make_pair(keyEnd, extraIt->second);
// closeRange for erase is this iterator
// insert (keyEnd, prevIterator->second) as well!
}
// 4 canonical conflicts:
// beginExtra w/ mid
// before-mid w/ mid (beginHasExtra==false)
// mid w/ endExtra
// mid w/ after-mid (endHasExtra==false)
bool insertMid = true;
if (beginHasExtra) {
if (beginExtra.second == val)
insertMid = false;
} else {
if (itBegin != m_map.begin()) {
typename std::map<K,V>::const_iterator beforeMid = itBegin;
--beforeMid;
if (beforeMid->second == val)
insertMid = false;
}
}
if (endHasExtra) {
if ( (insertMid && endExtra.second == val) || (!insertMid && endExtra.second == beginExtra.second) )
endHasExtra = false;
} else {
if ( (insertMid && itEnd!=m_map.end() && itEnd->second == val) || (!insertMid && itEnd!=m_map.end() && itEnd->second == beginExtra.second) )
itEnd = m_map.erase(itEnd);
}
itBegin = m_map.erase(itBegin, itEnd);
if (beginHasExtra)
itBegin = m_map.insert(itBegin, beginExtra);
if (insertMid)
itBegin = m_map.insert(itBegin, std::make_pair(keyBegin, val));
if (endHasExtra)
m_map.insert(itBegin, endExtra);
// INSERT YOUR SOLUTION HERE
}
// look-up of the value associated with key
V const& operator[]( K const& key ) const {
return ( --m_map.upper_bound(key) )->second;
}
};
@maybesravan
Copy link

This version did not pass the running time test:

 void assign(K const& keyBegin, K const& keyEnd, V const& val)
    {
        if (!(keyBegin < keyEnd))
        {
            return;
        }

        auto endIt = m_map.lower_bound(keyEnd);
        if ((endIt == m_map.end()) || (keyEnd < endIt->first))
        {
            const auto& valEnd =
                (endIt == m_map.begin()) ? m_valBegin : std::next(endIt, -1)->second;
            if (!(valEnd == val))
            {
                endIt = m_map.emplace_hint(endIt, keyEnd, valEnd);
            }
        } else if (endIt->second == val)
        {
            ++endIt;
        }

        auto startIt = m_map.lower_bound(keyBegin);
        if ((startIt == m_map.begin()) && (val == m_valBegin))
        {
            if (startIt != endIt)
            {
                m_map.erase(startIt, endIt);
            }
            return;
        } else if ((startIt != m_map.begin()) && (val == std::next(startIt, -1)->second))
        {
            --startIt;
        } else
        {
            if (keyBegin < startIt->first)
            {
                startIt = m_map.emplace_hint(startIt, keyBegin, val);
            } else
            {
                startIt->second = val;
            }
        }

        if (++startIt != endIt)
        {
            m_map.erase(startIt, endIt);
        }
    }

Only way i've found to possibly improve it:

...
       auto endIt = m_map.lower_bound(keyEnd);
       if ((endIt == m_map.end()) ||
           (keyEnd < endIt->first))
       {
           if ((endIt == m_map.begin()))
           {
               if (!(val == m_valBegin))
               {
                   endIt = m_map.emplace_hint(endIt, keyEnd, m_valBegin);
               }
           } else if (!(val == std::next(endIt, -1)->second))
           {
               auto node  = m_map.extract(std::next(endIt, -1));
               node.key() = keyEnd;
               endIt      = m_map.insert(endIt, std::move(node));
           }
       } else if (endIt->second == val)
       {
           ++endIt;
       }
...

Cannot test since there are only two attempts

did u sucess in the test? share the solution

@netmonitoring
Copy link

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

@sakib-shekh
Copy link

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

i have test link

@netmonitoring
Copy link

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

i have test link

Send me your direct contacts

@sakib-shekh
Copy link

sakib-shekh commented Mar 25, 2024

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

i have test link

Send me your direct contacts
hey buddy i also have implemented something but i am unclear about some case what to do can you explain your code and possibilities through gmeet my email sakibshekhabd@gmail.com

reply fast just 2 hours left

@triptisingla
Copy link

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

Can you please give the 1st solution?

@RutulPatel007
Copy link

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

Can you give your 1st solution

@alexismailov2
Copy link

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

Finally ThinkCells will be able to interview someone for this 10 years🤣🤣🤣

@RutulPatel007
Copy link

Can you give your solution @netmonitoring

@RutulPatel007
Copy link

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

i have test link

Send me your direct contacts

I have test link
email: githubrp@gmail.com

@netmonitoring
Copy link

Can you give your solution @netmonitoring

I will provide the solution to the test link directly. Will not allow modify my solution. So if you are not ready to provide your link, do not share your contacts.

Also i will ask you not share my solution anywhere.

@alexismailov2
Copy link

@netmonitoring what means test link?

@alexismailov2
Copy link

@RutulPatel007 @netmonitoring @triptisingla @sakib-shekh
Just remember this cartoon 🤣🤣🤣
IMG_2186

@NIGHTMARE09
Copy link

This was my approach:

#include <bits/stdc++.h>
template<typename K, typename V>
class interval_map {
    friend void IntervalMapTest();
    V m_valBegin;
    std::map<K,V> m_map;

public:
    // Constructor associates whole range of K with val by inserting (K_min, val) into the map
    interval_map(V const& val) {
        m_map.insert(m_map.end(), std::make_pair(std::numeric_limits<K>::lowest(), val));
    }

    // Assign value val to interval [keyBegin, keyEnd).
void assign( K const& keyBegin, K const& keyEnd, V const& val ) {
    // Check if the interval is valid
    if (!(keyBegin < keyEnd))
        return;

    // Initialize the map if it's empty
    if (m_map.empty()) {
        if (!(val == m_valBegin)) {
            m_map.insert(m_map.end(),std::make_pair(keyBegin, val));
            m_map.insert(m_map.end(),std::make_pair(keyEnd, m_valBegin));
        }
        return;
    }

    // Find a position to insert keyBegin
    auto insertPosBegin = m_map.lower_bound(keyBegin);
    bool insertBeforeBegin = false;

    // Check if keyBegin can be inserted before the beginning
    if (insertPosBegin == m_map.begin() && val == m_valBegin)
        return; // Value at the beginning cannot be equal to m_valBegin.

    // Check if keyBegin can be inserted before insertPosBegin
    if ((insertPosBegin == m_map.end()) || (insertPosBegin != m_map.begin() && (keyBegin < insertPosBegin->first || std::prev(insertPosBegin)->second == val)))
        --insertPosBegin;
    else if (insertPosBegin == m_map.begin() && keyBegin < insertPosBegin->first)
        insertBeforeBegin = true;

    // Find a position to insert keyEnd
    auto insertPosEnd = m_map.lower_bound(keyEnd);
    bool insertBeforeEnd = false;

    auto tempPos = insertPosEnd;

    // Check if keyEnd can be inserted before insertPosEnd
    if (insertPosEnd == m_map.end() || (keyEnd < insertPosEnd->first && insertPosEnd != m_map.begin()))
        --tempPos;
    else if (insertPosEnd == m_map.begin() && keyEnd < insertPosEnd->first)
        insertBeforeEnd = true;

    auto endElementPair =  std::pair<K,V>(keyEnd, (insertBeforeEnd ? m_valBegin : tempPos->second));

    // Insert or assign keyBegin
    if (insertBeforeBegin || !(insertPosBegin->second == val)) {
        insertPosBegin = m_map.insert(insertPosBegin, {keyBegin, val});
    }

    // Erase elements between keyBegin and keyEnd
    auto tempIter = insertPosBegin;
    if (insertPosBegin != m_map.end())
        ++tempIter;

    // Delete elements between inserted begin key and end key position
    if (tempIter != m_map.end() && !(keyEnd < tempIter->first)) {
        m_map.erase(tempIter, insertPosEnd);
    }

    // Insert or assign keyEnd
    if (!(insertPosBegin->second == endElementPair.second)) {
        insertPosEnd = m_map.insert(insertPosEnd, {endElementPair.first, endElementPair.second});
    }

    // Delete end element if its value is same as begin element value
    if (insertPosEnd != m_map.end() && insertPosBegin->second == insertPosEnd->second) {
        m_map.erase(insertPosEnd);
    }
}


    // Look-up of the value associated with key
    V const& operator[](K const& key) const {
        auto it = m_map.upper_bound(key);
        if (it == m_map.begin()) {
            return m_valBegin;
        } else {
            return std::prev(it)->second;
        }
    }
};

// Driver or test code
int main() {
    interval_map<int,char> m('A');
    // calling of assign() function  
    m.assign(1, 3, 'B');
    m.assign(4, 8, 'F');
    m.assign(6, 11, 'V');
    m.assign(11, 15, 'F');
    m.assign(0, 3, '2');
    m.assign(0, 5, '3');
    m.assign(1, 5, '2');
    m.assign(1, 4, '2');
    m.assign(1, 4, '3');
    m.assign(1, 5, 's');
    m.assign(1, 5, 'r');
    m.assign(8, 10, 's');
    m.assign(4, 8, 's');
    m.assign(1, 8, 's');
    m.assign(1, 8, 'o');
    m.assign(1, 2, 'k');
    m.assign(-10, 4, 2);
    m.assign(-10, -2, 2);
    m.assign(-10, -2, 3);
    m.assign(-10, -2, 0);
    m.assign(-10, 0, 2);
    m.assign(-10, 3, 2);
    m.assign(-10, 3, 1);
    m.assign(-10, 1, 2);
    m.assign(-10, 4, 2);
    m.assign(-10, 8, 2);
    m.assign(-10, 3, 0);
    m.assign(0, 5, 0);
    m.assign(1, 5, 0);
    m.assign(1, 8, 0);
    m.assign(3, 4, 0);
    m.assign(3, 4, 1);
    m.assign(3, 5, 1);
    m.assign(3, 5, 2);
    m.assign(5, 8, 2);

    // loop for mapping key and its corresponding value
    for (int i = -2; i <= 19; ++i)
        std::cout << std::setw(2) << i << ' ' << m[i] << '\n';

}

But my program didn't pass the Correctness criteria. I don't know why. I have tested multiple test scenarios and it was working just fine. This test is so fucking baseless, it is concerning how a developer actually works in the job here.

Correctness: Your program should produce a working interval_map with the behavior described above. In particular, pay attention to the validity of iterators. It is illegal to dereference end iterators. Consider using a checking STL implementation such as the one shipped with Visual C++ or GCC. Many solutions we receive do not create the data structure that was asked for, e.g., some interval ends up being associated with the wrong value. Others contain a code path that will eventually dereference an invalid or end iterator.

@glezmen
Copy link

glezmen commented Jun 22, 2024

Hi,

I just failed the 'Correctness' test, but I really have no idea why. I have MANY test cases, tried to be really tricky with my testing, but everyhting appeared to work, the online submission still failed.

Can someone tell me what was wrong with my solution?

		if (! (keyBegin < keyEnd)) {
			return; // invalid range
		}
		auto del_begin{m_map.lower_bound(keyBegin)};
		auto del_end = del_begin; // {m_map.upper_bound(keyEnd)};
		while (del_end != m_map.end() && del_end->first < keyEnd) {
			++del_end;
		}

		// get left neighbour of our range
		auto left{del_begin == m_map.begin() ? m_map.end() : std::prev(del_begin)};

		// get right neighbour of our range
		//auto rightVal = this->operator[](keyEnd);
		auto rightVal{del_end == m_map.begin() ? m_valBegin : std::prev(del_end)->second};

		// erase obsolete
		del_end = m_map.erase(del_begin, del_end);

		// add new begin
		if (left == m_map.end() || left->second != val) {
			m_map.emplace_hint(del_end, keyBegin, val);
		}

		// add new end
		if ((del_end == m_map.end() || del_end->second != val) && rightVal != val) {
			m_map.emplace_hint(del_end, keyEnd, rightVal);
		}

@Ragab2010
Copy link

Ragab2010 commented Jul 8, 2024

I have two solutions for this task. First one passed successfully, due to that i had no chance to check if second solution is also correct. If somebody have a link to online test and wants to check my second solution write me a pm.

I have the links send to me the solution to test it . ragabmmx@gmail.com

@glezmen
Copy link

glezmen commented Jul 12, 2024

keep trying

Yep, that would be great, but you only have two chance to produce a perfect solution without knowing the test cases or some details, so you have to guess. And if you guess wrong - you're out without any explanation.

@netmonitoring
Copy link

netmonitoring commented Jul 12, 2024

image

I passed the test the other day! For those of you like me who will have nightmares if they don't find the solution, rest assured—it does have a solution. So keep trying

My solution ended up being 20 lines of code. You'd need to use basic algorithms you may not have used since you were in school.

Their code tests are good, but they may be stateless and might not account for some conditions, so they might tell you that your answer is wrong. For instance, you might be sure part of your code would only be executed on empty sets of data; therefore, you might not include some bits that would formally reduce the complexity. The test would fail there.

Read each requirement carefully and create tests for your code.

ChatGPT won't be much help with the problem itself, but if you can break it into parts, it may help you produce your solution faster.

Don't bother contacting them with your answer—they will reply with a prefabricated email that won't give you any useful information or review.

I'm missing a certification or badge for those who pass the test.

I encourage everyone to take the test. It's not a scam; it's just a fair way of choosing employees. If you like games, logic, and solving problems, it's something you'll enjoy. However, if you don't manage to get the answer, you may lose sleep for some time.

Good luck!

My code takes about 60 lines and I had a bit different message, when passed the test, see below:

image

@Ragab2010
Copy link

Ragab2010 commented Jul 12, 2024

image
I passed the test the other day! For those of you like me who will have nightmares if they don't find the solution, rest assured—it does have a solution. So keep trying
My solution ended up being 20 lines of code. You'd need to use basic algorithms you may not have used since you were in school.
Their code tests are good, but they may be stateless and might not account for some conditions, so they might tell you that your answer is wrong. For instance, you might be sure part of your code would only be executed on empty sets of data; therefore, you might not include some bits that would formally reduce the complexity. The test would fail there.
Read each requirement carefully and create tests for your code.
ChatGPT won't be much help with the problem itself, but if you can break it into parts, it may help you produce your solution faster.
Don't bother contacting them with your answer—they will reply with a prefabricated email that won't give you any useful information or review.
I'm missing a certification or badge for those who pass the test.
I encourage everyone to take the test. It's not a scam; it's just a fair way of choosing employees. If you like games, logic, and solving problems, it's something you'll enjoy. However, if you don't manage to get the answer, you may lose sleep for some time.
Good luck!

My code takes about 60 lines and I had a bit different message, when passed the test, see below:

image

can you write all the test cases with the correct output to fix our implementation, or explain the problem clearly, or send the passed code : ragabmx2002@gmail.com

@Devansh2895
Copy link

Devansh2895 commented Jul 14, 2024

@jonathan-ruiz Can you please send the test cases you used to test your solution so that I can keep trying and improve my solution, taking this test today. Thanks.
devansh2895@gmail.com

@Devansh2895
Copy link

Devansh2895 commented Jul 14, 2024

 auto endIt = m_map.lower_bound(keyEnd);

@maybesravan You are using too many methods of cost Log(N), you can achieve the expected result using just one check in the documentation the cost of the methods you are using.

Do you mean we have to avoid lower_bound method twice and just use it once?

@DevanshChugh
Copy link

@netmonitoring can you share you solution that passed on devanshchugh04@gmail.com

@nanomatters
Copy link

nanomatters commented Jul 16, 2024

Here is one take without using upper/lower bound checks. I shortly checked against a normal array and if it is canonical, but didn't check the boundaries. One concern I had was whether the eraseEnd iterator will be invalidated if the lower bound is inserted but according to the standard it should not be the case for std::map. It is not a submitted code, so use the idea at your own risk.

PS: Really, we shouldn't use even insert() Then why are we using a map?

void assign( K const& keyBegin, K const& keyEnd, V const& val ) {
    // incorrect key
    if ( keyEnd <= keyBegin )
        return;

    const auto &[ upperBoundItr, upperBoundSuccess ] = m_map.insert( { keyEnd, val } );
    auto eraseEnd = upperBoundItr;

    // upper boundary should be the continuation of the previous range. if it is a new insertion
    // it should have the previous range value. if the insertion was not successful, the value should not change.
    if ( upperBoundSuccess ) {
        upperBoundItr->second = std::prev( upperBoundItr )->second;

        // if it is a new insertion, we need to check if the next boundary has the same value.
        if ( auto n = std::next( eraseEnd ); n != m_map.cend() && n->second == eraseEnd->second )
            m_map.erase( n );
    }

    const auto &[ lowerBoundItr, lowerBoundSuccess ] = m_map.insert_or_assign( keyBegin, val );
    auto eraseStart = std::next( lowerBoundItr );

    // if the end of the range has the same value, the end boundary should be removed.
    if ( lowerBoundItr->second == eraseEnd->second )
        eraseEnd = std::next( eraseEnd );

    // if the previous start boundary has the same value, remove the new duplicate.
    if ( lowerBoundItr != m_map.cbegin() && std::prev( lowerBoundItr )->second == val )
        eraseStart = lowerBoundItr;

    m_map.erase( eraseStart, eraseEnd );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment