2015.03.最新面试题(1)

Q1:  给出列表:
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;
}


 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值