Q1:
给出列表:
1: a, b
2: b, c
3: e
4: a
(1, 2, 4) (a, b, c)
1: a, b
2: b, c
3: e
4: a
...
(1, 2, 4) (a, b, c)
(3) (e)
分析: 这道题思路很简单,就是用按照顺序合并,对于每一个列表的row,检查是否能和以前的值合并.
但是要格外注意的是,每个输入的row可能同时与前几个值都可以合并,只是要把它们全部合并在一起.
C++实现如下:
class MySet{
vector<string> roots_;
unordered_set<string> values_;
public:
MySet(const string& s){
makeSet(s);
}
void makeSet(const string& s){
int start = 0;
int end = s.find(':');
roots_.push_back(s.substr(start, end-start));
start = end+1;
end = s.find(',', start);
while(end!=string::npos){
values_.insert(s.substr(start, end-start));
start = end+1;
end = s.find(',', start);
}
values_.insert(s.substr(start, s.size()-start));
}
bool joinable(const MySet& other){
unordered_set<string>::const_iterator it;
for(it=other.values_.begin(); it!=other.values_.end();++it){
if(values_.count(*it)) return true;
}
return false;
}
void join(const MySet& other){
for(int i=0; i<other.roots_.size(); ++i){
roots_.push_back(other.roots_[i]);
}
unordered_set<string>::const_iterator it;
for(it=other.values_.begin(); it!=other.values_.end();++it){
values_.insert(*it);
}
}
void print(){
cout << "(" << roots_[0];
for(int i=1; i<roots_.size(); ++i){
cout << "," << roots_[i];
}
cout << ")";
unordered_set<string>::iterator it;
it = values_.begin();
cout << "(" << *it;
++it;
for(; it!=values_.end(); ++it){
cout << "," << *it;
}
cout << ")" << endl;
}
};
void combine_rows(const vector<string>& table){
if(table.empty()) return;
typedef list<MySet>::iterator Iter;
list<MySet> result;
result.emplace_back(table[0]);
for(int i=1; i<table.size(); ++i){
MySet temp(table[i]);
// temp.print();
vector<Iter> joinable_list;
for(Iter it=result.begin(); it!=result.end(); ++it)
{
if(it->joinable(temp)){
joinable_list.push_back(it);
}
}
result.push_front(temp);
for(int j=0; j<joinable_list.size(); ++j){
result.front().join(*(joinable_list[j]));
result.erase(joinable_list[j]);
}
}
for(Iter it=result.begin(); it!=result.end(); ++it){
it->print();
}
}
Q2. 写一个random函数,产生0 ~ n-1的数,但是有一个black list,产生的数不能在black
list里。 bl是sorted的。
int myRandom(int n, vector<int> bl)
{
//.....
}.
时间复杂度log(n)
分析: 这道题用mapping非常trivial, 而且有disadvantage. 譬如blacklist里面有几百万个数怎么办?几百万个数就是~400MB,超过了CPU的
缓存的大小。如果建hash table,性能会损失非常大。正确的解法是用binary search.
C++实现如下:
int random(int n, const vector<int>& bl)
{
if(n==bl.size()) return -1;
int r = rand()%(n-bl.size());
if (bl.size()==0 || r<bl[0]) return r;
cout << r << " : ";
int offset = r - bl[0] + 1;
int left = 0, right=bl.size()-1;
while (left+1 < right) {
int m = (left + right) / 2;
cout << bl[left]+offset << ", ";
// number of non black list numbers on left
int available_nums = (bl[m] - bl[left]) - (m - left);
if (available_nums < offset) {
offset -= available_nums;
left = m;
} else {
right = m;
}
}
if (offset > (bl[right] - bl[left]) - (right - left)) {
offset++;
}
return bl[left] + offset;
}