高端笔试题-Inter美国职位

 Inter美国职位的面试题,师兄对c++不是很熟,让我帮忙写。看了题目写了后感觉这职位就是为我量身定做的呀T_T,但是人家PHD only。。。

题目是给一个高纬矩阵,维数和每一维的长度都未知,但是每一维的长度都是2^x,即2^d1, 2^d2,..., 2^dn,让对这各矩阵downsample,也就是数据降维。每次降维就是把原矩阵降成 2^(d1-1), 2^(d2-1),..., 2^(dn-1)维,降次就可以得到一个小矩阵,直到降到某一维长度1,输出每一次降维得到的矩阵。

降维后矩阵的值由原矩阵中出现次数最多的数字代替,每次降维都必须由原始矩阵得到新值,而不能用中间降维得到的矩阵得到新值。

例如:

00000000

10101010

11001100

11101110

00001111

10101111

11101100

11001101

yields the 1-downsampled image

0000

1010

0011

1010

the 2-downsampled image

00

01

and the 3-downsampled image

1

最后一次得1得原因是原始矩阵中1出现最多,而不是根据2-downsampled里的值来输出0


如果你认为这就完了,那么你就错了。。毕竟这是招PHD的,薪水还好高好高。。

题目要求用多线程实现,用BOOST库,还要分析时间空间利用与线程数,矩阵大小和矩阵中值的种类的关系。

下面是题目的一下要求:

2. EFFICIENCY

Your code should use the fastest possible parallel algorithm. Answer the following questions about computational complexity.

Let N be the number of pixels in the original image, n the number of unique pixel values in the original image, and M the number of parallel threads.

(1) How does the execution time of the fastest parallel algorithm scale with N, n, andM?

(2) How does memory usage scale with N, n, and M?

3. STYLE

The style of your code will be evaluated, including aspects such as

• organization into functions

• object-oriented design

• memory management

下面是我的解法了:由于矩阵的维数和各维的长度都未知,我用了类似c语言的一维矩阵模拟高维矩阵,手动计算下表。用多线程将矩阵分割,然后每个线程处理一块。用一个Index(map< pair<level, blockIndex>, <value, times> >)数据结构存放线程结果。最后汇总一下得到最终结果。

上代码!!!!真是高端面试题呀。。

#include <iostream>
#include <algorithm>
#include <string>
#include <fstream>
#include <vector>
#include <map>

#include <boost/lexical_cast.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>

template<class T>
class Matrix {
public:
    Matrix():_d(0), _p(NULL){
    }
    Matrix(int d, int *base): _d(d) {
        size_t num = 1;
        for(int i=0; i<d; ++i) {
            _base[i] = base[i];
            num *= _base[i];
        }
        _p = new T[num];
    }
    Matrix(const Matrix<T> & m):_d(m._d) {
        for(int i=0; i<_d; ++i) {
            _base[i] = m._base[i];
        }
        size_t s = m.size();
        _p = new T[s];
        for(int i=0; i<size(); ++i) {
            _p[i] = m._p[i];
        }
    }
    Matrix<T> & operator=(const Matrix<T> & x) {
        if(this == &x) {
            return *this;
        }

        _d = x._d;
        for(int i=0; i<x._d; ++i) {
            _base[i] = x._base[i];
        }
        if(_p)
            delete[] _p;
        size_t s = x.size();
        _p = new T[s];
        for(int i=0; i<s; ++i) {
            _p[i] = x._p[i];
        }
        return *this;
    }
    size_t size() const{
        if(!_d) return 0;
        size_t re = 1;
        for(int i=0; i<_d; ++i) {
            re *= _base[i];
        }
        return re;
    }
    T & get(int *ind) const{
        size_t pod = 1, index = 0;
        for(int i=_d-1; i>=0; --i) {
            index += ind[i] * pod;
            pod *= _base[i];
        }
        return _p[index];
    }
    void assign(int *ind, const T &t) {
        size_t pod = 1, index = 0;
        for(int i=_d-1; i>=0; --i) {
            index += ind[i] * pod;
            pod *= _base[i];
        }
        _p[index] = t;
    }
    int getd() const {
        return _d;
    }
    int getBase(int i) const {
        return _base[i];
    }
    int getMinBase() const{
        return *std::min_element(_base, _base+_d);
    }

    void output() const {
        size_t s = size();
        for(int i=0; i<s; ++i) {
            std::cout << _p[i] << " ";
        }
        std::cout << std::endl;
    }
    ~Matrix(){
        delete[] _p;
    }
private:
    T *_p;
    int _d, _base[64];
};

template<class T>
class MatrixReader {
public:
    Matrix<T> read(std::istream &in){
        int d, ind[64], index[64];
        in >> d;
        for(int i=0; i<d; ++i) {
            in >> ind[i];
        }

        Matrix<T> re(d, ind);
        while(in) {
            for(int i=0; i<d; ++i) {
                in >> index[i];
            }
            T value;
            in >> value;
            re.assign(index, value);
        }
        return re;
    }
    Matrix<T> read(const std::string &fileName) {
        std::ifstream in(fileName.c_str());
        return read(in);
    }
};

template<class T>
class DownSample {
public:
    typedef std::map< std::pair<int, int>, std::map<T, int> > Index; //map< std::pair<level, blockIndex>, std::map<num, times>>
    //block of the original matirx
    //baseIntever[i][0] -> start index of i'th dimension
    //baseIntever[i][1] -> length of i'th dimesion
    struct Arg {
        int baseIntever[64][2];
        void output(int d) const{
            std::cout << "[TEST]" << std::endl;
            for(int i=0; i<d; ++i) {
                std::cout << baseIntever[i][0] << " " << baseIntever[i][1] <<std::endl;
            }
        }
    };
    DownSample(const Matrix<T>& m) :_m(m){
    }
    void downSample(int threadNum = 1) {
        for(int i=0; i<32; ++i) {
            if((1<<i) > threadNum) {
                threadNum = (1<<(i-1));
                break;
            }
        }
        int mn = _m.getMinBase();
        int ind[64];
        for(int i=0; i<_m.getd(); ++i) {
            ind[i] = _m.getBase(i);
        }
        for(int k=mn; k>1; k/=2) {
            for(int j=0; j<_m.getd(); ++j) {
                ind[j] /= 2;
            }
            _re.push_back(Matrix<T>(_m.getd(), ind));
        }

        //ind[i] -> the i'th dimension is cut to ind[i] parts
        for(int i=0; i<_m.getd(); ++i) {
            ind[i] = 1;
        }
        for(int i=0; i<_m.getd(); ++i) {
            int num = _m.getBase(i);
            if(threadNum <= num) {
                ind[i] = threadNum;
                break;
            } else {
                ind[i] = num;
                threadNum /= ind[i];
            }
        }

        int threadInUse = 1;
        for(int i=0; i<_m.getd(); ++i) {
            threadInUse *= ind[i];
        }
        std::cout << "[TEST] minbase = " << mn << " threadInUse = " << threadInUse<< std::endl;

        std::vector<Arg> args;
        Arg x;
        dfsGetArg(ind, args, 0, x);
        /*
        std::cout << "[TEST] ARGS" << std::endl;
        for(int i=0; i<args.size(); ++i) {
            args[i].output(_m.getd());
        }
        */
        boost::thread_group group;
        for (size_t i = 0; i < threadInUse; ++i) {
            group.create_thread(boost::bind((&DownSample::callBack), this, args[i], i));
        }
        group.join_all();
        int p[64];
        for(typename Index::iterator it = _index.begin(); it != _index.end(); ++it) {
            int lev = (it->first).first;
            int block = (it->first).second;
            int factor = 1;
            //decode "block" to dimension indexes
            for(int i=1; i<_m.getd(); ++i) {
                factor *= _m.getBase(i) / (1<<(lev+1));
            }
            for(int i=0; i<_m.getd(); ++i) {
                p[i] = block / factor;
                block %= factor;
                if(i+1 < _m.getd())
                    factor /= _m.getBase(i+1) / (1<<(lev+1));
            }
            T val = 0, times = 0;
            for(typename std::map<T, int>::iterator jt = it->second.begin(); jt != it->second.end(); ++jt) {
                if( jt->second > times) {
                    times = jt->second;
                    val = jt->first;
                }
            }
            /*
            std::cout << "[TEST] " << "level = " << lev;
            std::cout << " index = ";
            for(int i=0; i<_m.getd(); ++i) {
                std::cout << "[" << p[i] << "]";
            }
            std::cout << " value = " << val << std::endl;
            */
            _re[lev].assign(p, val);
        }
    }
    //full permutition to get every block of the original matrix
    void dfsGetArg(const int *ind, std::vector<Arg> &args, int now, Arg &th) {
        if(now >= _m.getd()) {
            args.push_back(th);
            return ;
        }
        for(int i=0; i<ind[now]; ++i) {
            th.baseIntever[now][0] = i * (_m.getBase(now) / ind[now]);
            th.baseIntever[now][1] = (_m.getBase(now) / ind[now]);
            dfsGetArg(ind, args, now+1, th);
        }
    }
    void callBack(const Arg & x, int threadLabel) {
        std::cout << "[INFO] start " << threadLabel << " thread" << std::endl;
        int level = _re.size();
        //map< std::pair<level, blockIndex>, std::map<num, times>>
        int offset[64];
        dfsGetIndex(x, level, 0, offset);
        return ;
    }
    //full permutition to get every element from Arg x'block
    void dfsGetIndex(const Arg & x, int level, int now, int *offset) {
        if(now >= _m.getd()) {
            int p[64]; //index of every element in this block
            for(int i=0; i<_m.getd(); ++i) {
                p[i] = offset[i] + x.baseIntever[i][0];
            }
            T value = _m.get(p);
            for(int i=0; i<level; ++i) {
                int blockIndex = 0;
                int factor = 1;
                //incode index p[] to i'level matrix
                for(int j=_m.getd()-1; j>=0; --j) {
                    blockIndex += ( p[j] / (1<<(i+1)) ) * factor;
                    factor *= (_m.getBase(j) / (1<<(i+1)) );
                }
                boost::unique_lock< boost::mutex > lock(_mtx);
                ++_index[ std::make_pair(i, blockIndex) ][value];
            }
            return ;
        }
        for(int i=0; i<x.baseIntever[now][1]; ++i) {
            offset[now] = i;
            dfsGetIndex(x, level, now+1, offset);
        }
    }
    void outputResult() const {
        std::cout << "[INFO] result one line a matrix" << std::endl;
        for(int i=0; i<_re.size(); ++i) {
            _re[i].output();
        }
    }
private:
    const Matrix<T> &_m;
    std::vector< Matrix<T> > _re;
    Index _index;
    boost::mutex _mtx;
};

int main(int argc, char* argv[]) {
    if( argc != 3 ) {
        std::cout << "Usage: " << argv[0] << " fileName threadNum" << std::endl;
        exit(0);
    }
    MatrixReader<int> r;
    Matrix<int> m = r.read(argv[1]);
//    m.output();
    DownSample<int> down(m);
    down.downSample(boost::lexical_cast< int >(argv[2]));
    down.outputResult();
    return 0;
}
/*
compile command:
g++ -g -std=c++11 Matrix.cpp -lboost_thread -lboost_system -lpthread -o a.out
*/
/*
example of input file
2  -> dimension numbers
4 8 -> base of every dimension
0 0 1
0 1 1
0 2 1
0 3 1
0 4 1
0 5 1
0 6 1
0 7 1
1 0 1
1 1 2
1 2 1
1 3 2
1 4 1
1 5 2
1 6 1
1 7 2
2 0 1
2 1 1
2 2 2
2 3 2
2 4 2
2 5 2
2 6 2
2 7 2
3 0 1
3 1 2
3 2 2
3 3 2
3 4 2
3 5 2
3 6 2
3 7 2
*/


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值