我在其中一家IT公司发送了一份关于C ++职位的申请。他们给我发了一份测试任务。
任务是实现间隔图分配操作。我向他们发送了我的解决方案,但它没有通过第二个要求(正确的行为)。他们没有给出反馈,而是说我的代码没有通过他们所有的测试。现在我想知道我能做错什么。当然,在发送我的解决方案之前,我做了一些测试,并且我能想到的每一个测试都通过了。
现在我无法入睡而不知道我在哪里搞砸了。
这是我的代码:
void assign (const K & keyBegin, const K & keyEnd, const V & val )
{
if (!(keyBegin < keyEnd))
return;
auto nextInterval = --m_map.upper_bound(keyEnd);
auto inserted1 = m_map.end();
auto inserted2 = m_map.end();
if (nextInterval->second == val)
++nextInterval;
else if (nextInterval->first < keyEnd)
{
const V & nextValue = nextInterval->second;
++nextInterval;
inserted1 = nextInterval = m_map.emplace_hint(nextInterval, keyEnd, nextValue);
}
try
{
auto prevInterval = nextInterval;
--prevInterval;
if (keyBegin < prevInterval->first)
prevInterval = --m_map.upper_bound(keyBegin);
if (!(prevInterval->second == val))
{
if (prevInterval->first < keyBegin)
{
++prevInterval;
inserted2 = prevInterval = m_map.emplace_hint(prevInterval, keyBegin, val);
}
else
{
auto beforePrev = prevInterval;
--beforePrev;
if (beforePrev != m_map.end() && beforePrev->second == val)
prevInterval = beforePrev;
else
{
auto hint = m_map.erase(prevInterval);
inserted2 = prevInterval = m_map.emplace_hint(hint, keyBegin, val);
}
}
}
m_map.erase(++prevInterval, nextInterval);
}
catch (...)
{
if (inserted1 != m_map.end())
m_map.erase(inserted1);
if (inserted2 != m_map.end())
m_map.erase(inserted2);
throw;
}
}
你能帮我找个错误吗?
答案 0 :(得分:3)
你通过递减地图的开头来获得UB:
auto beforePrev = prevInterval;
--beforePrev;
您的以下测试也很奇怪:
if (beforePrev != m_map.end()
beforePrev在递减时不能是end()
。
似乎你可以用
替换那个块prevInterval->second = val;
if (prevInterval != m_map.begin() && !((--prevInterval)->second == val)){
++prevInterval;
}
答案 1 :(得分:2)
Vivek的上述两个解决方案不起作用。这是我能想到的最简单,最短的实现:
if (not (keyBegin < keyEnd) )
return;
auto beginLowerBound = m_map.lower_bound(keyBegin);
auto endLowerBound = m_map.lower_bound(keyEnd);
std::optional<std::pair<K,V>> additionalElement;
if (endLowerBound == m_map.end() || keyEnd < endLowerBound->first)
additionalElement = std::pair(keyEnd, operator[]( keyEnd ));
else if (beginLowerBound == m_map.end() || keyBegin < beginLowerBound->first)
additionalElement = std::pair(keyEnd, operator[]( keyBegin ));
if (beginLowerBound != m_map.end())
m_map.erase(beginLowerBound, endLowerBound);
m_map.insert(std::pair(keyBegin, val));
if (additionalElement)
m_map.insert(additionalElement.value());
答案 2 :(得分:1)
首先编写测试代码: 这是为了测试类型要求
class Value {
char a;
public:
Value(char _a){ a = _a; }
bool operator==(const Value& _val) const;
friend ostream& operator<<(ostream& os, const Value& val); // ONLY FOR TESTING, NOT RELATED TO SOLUTION
};
bool Value::operator==( const Value& _val ) const{
return ( a == _val.a ) ;
}
// operator<< is implemented ONLY FOR TESTING PURPOSE
ostream& operator<<(ostream& os, const Value& val)
{
os << val.a;
return os;
}
class Key {
int a;
public:
Key(int _a){ a = _a; }
Key(){ a = 0; }
bool operator<(const Key& _key) const;
friend ostream& operator<<(ostream& os, const Key& _key); // ONLY FOR TESTING, NOT RELATED TO SOLUTION
};
bool Key::operator<( const Key& _key ) const{
return ( a < _key.a ) ;
}
// operator<< is implemented ONLY FOR TESTING PURPOSE
ostream& operator<<(ostream& os, const Key& _key)
{
os << _key.a;
return os;
}
现在实施
void assign( K const& keyBegin, K const& keyEnd, V const& val ) {
K last = m_map.rbegin()->first;
K first = m_map.begin()->first;
if (!(keyBegin < keyEnd) ) return;
if ( keyBegin < first ) return;
if( last < keyEnd) return ;
for (auto it = m_map.begin(); it!=m_map.end(); ++it)
{
if((*it).first < keyBegin) continue;
else
{
(*it).second=val;
it++;
auto tmp=it;
while((*it).first < keyEnd){
it++;
}
m_map.erase(tmp, it);
break;
}
}
}
另一种解决方案
void assign( K const& keyBegin, K const& keyEnd, V const& val ) {
K last = m_map.rbegin()->first;
K first = m_map.begin()->first;
if (!(keyBegin < keyEnd) ) return;
if ( keyBegin < first ) return;
if( last < keyEnd) return ;
auto itr1 = m_map.find(keyBegin);
auto itr2 = m_map.find(keyEnd);
(*itr1).second=val;
itr1++;
m_map.erase(itr1,itr2);
cout << endl << endl;
}
答案 3 :(得分:0)
if (!(keyBegin < keyEnd))
return;
auto upper_bound_end = m_map.upper_bound(keyEnd);
auto upper_bound_end2 = upper_bound_end;
upper_bound_end2--;
auto uper_bound_begin = m_map.upper_bound(keyBegin);
auto uper_bound_begin2 = uper_bound_begin;
uper_bound_begin2--;
bool flag = false;
bool flag2 = false;
if (!((uper_bound_begin2)->second == val))
flag = true;
V tmp;
if (!((upper_bound_end2)->second == val))
{
flag2 = true;
tmp = (upper_bound_end2)->second;
}
for (auto it = uper_bound_begin; it != upper_bound_end;)
{
it = m_map.erase(it);
}
if (flag == true)
m_map[keyBegin] = val;
if (flag2 == true)
m_map[keyEnd] = tmp;
答案 4 :(得分:-1)
完整的工作代码,以下代码位于main()中 (但雇主说模板类型使用不正确)
#define _ITERATOR_DEBUG_LEVEL 2
#define _SECURE_SCL 1
#define _HAS_ITERATOR_DEBUGGING 1
#include <iostream>
#include <iomanip>
#include <cassert>
#include <map>
template<typename K, typename V>
class interval_map {
V m_valBegin;
std::map<K, V> m_map;
public:
// constructor associates whole range of K with val
interval_map(V const& val)
: m_valBegin(val)
{}
void assign(std::map<K, V> const& testMap) {
m_map = testMap;
}
// 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.
// 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 (--it)->second;
}
}
void print() {
std::cout << '\n' << m_valBegin << '\n';
for (auto it = m_map.begin(); it != m_map.end(); ++it) {
std::cout << it->first << ", " << it->second << '\n';
}
}
void assign(K const& keyBegin, K const& keyEnd, V const& val) {
if (!(keyBegin < keyEnd)) return;
if (m_map.empty()) {
if (m_valBegin == val)
return;
m_map.insert({ keyBegin, val });
m_map.insert({ keyEnd, m_valBegin});
return;
}
auto startIt = m_map.lower_bound(keyBegin);
bool doErase = true;
if (startIt == m_map.end())
doErase = false;
auto endIt = m_map.upper_bound(keyEnd);
auto upperVal{ m_valBegin };
if (endIt == m_map.begin())
doErase = false;
else
upperVal = (--endIt)->second;
if (endIt != m_map.end())
endIt++;
if(doErase)
m_map.erase(startIt, endIt);
m_map.insert({ keyBegin, val });
m_map.insert({ keyEnd, upperVal });
// ensure canonical - further down
startIt = m_map.lower_bound(keyBegin);
assert(startIt->second == val);
// go back to prev interval (it can have value = val)
if (startIt != m_map.begin())
{
startIt--;
// then our inserted value is the first equal to val
if (startIt->second != val)
startIt++;
}
// skip first repeating value (first one should be left - others deleted)
if(!(startIt == m_map.begin() && val == m_valBegin))
startIt++;
while(startIt != m_map.end())
{
auto tmpKey = startIt->first;
if ((startIt++)->second == val)
m_map.erase(tmpKey);
else
break;
}
}
};
int main() {
interval_map<int, char> mymap{ 'a' };
//mymap.assign({ {10,'c'},{20,'a'},{30,'c'},{40,'i'},{50,'c'},{60,'i'} });
//mymap.assign(65, 68, 'z'); mymap.print();
while (1)
{
mymap.print();
int start, end;
char ch;
std::cout << "\n\n Enter start, end, char: ";
std::cin >> start >> end >> ch;
mymap.assign(start, end, ch);
}
}