【编程之美】微软技面心得

1 给定N, 求出最小的M,使得N*M的结果十进制后,只包含0和1

搜索算法,运用余数优化


类似: 最快的办法求最大公约数: 

lcd (x, y) = ( if x&1 && y&1:  lcd(x, (x-y)/2);   else  lcd(x/2 if x&1==0, y/2 if y&1==0) )


2 精确表达浮点数(循环节):

x=x1x2..xi . y1y2...yj (z1 z2... zk)  ={ x1x2..xi y1y2...yj}/10^j + m/10^j

其中 循环节 m = z1 z2 ... zk/ (10^k -1)

所以 x = [  { x1x2..xi y1y2...yj} +  {z1 z2 ... zk}/ (10^k -1)  ] /10^j 

          [  { x1x2..xi y1y2...yj}* (10^k -1) +{z1 z2 ... zk}  ]/ [ (10^k -1)*(10^j ) ], 化简就可。

反向: 给出 n,m 求 n/m的循环节:

n/m = k + 0.y1y2...yj (z1 z2... zk) 

t/m = 0.y1y2...yj (z1 z2... zk) = y/10^j + z/ [ 10^j *(10^k - 1) ]

一个重要的结论是 0.(z1z2...zk) = {z1z2..zk}/(10^k-1),  比如 0.(353) =  353/(1000-1) = 353/999.


2  给定a1~ak,以及推导公式ak+1 <= a1~ak,最快的办法求到 an

方法:矩阵加速(专用于求解k阶递推数列) 或 特征方程(会存在无理数)


3 寻找最近点对距离、最远点距离

二分(  按照纵线二分)

数组中找相邻数的最大差值(分 桶)


4 数组分割

转化为带物品数量限制的背包重量问题 , O(N^2*Sum),N=obj_cnt, Sum=w_total

//bool[i][j]: 装i个物品,能否装到重量j

bool[0][0] = true

for k=1 to obj_cnt: //背包问题最外层迭代一定是物品,因为物品只能装一次

  for i=1 to obj_cnt/2:

        for j = w_total to obj_w[k]:

              bool[i][j] = bool[i-1][j] || bool[i-1][j-obj_w[k]] 


5 最短摘要的生成

类似于leetcode上面的最短包含了 指定数量的字母的字符串 , 用一个队列去保存当前摘要序列中的各个关键词出现的位置(按顺序),每次遇到一个新单词,把队首的多余单词去掉,更新当前序列的长度。。直到找到最短长度的序列。


6 桶中取黑白球算概率:

排列组合 + DP(类似还有卡特兰数f [ 2n ] = E( f[ 2n-2*i-2 ] * f[ 2*i ], i=0~n-1 ) =  C(2n, n) - C(2n, n-1) )

cnt[sum][white]为还剩下sum个球,白球数量white的概率排列组合数。

cnt[200][100] = 1

cnt[sum][white] = cnt[sum+1] [ white ]*3 + cnt[sum+1] [ white+2]   //四种取法,对应四种上一个状态

最后 cnt[1][0] / (cnt[1][0] + cnt[1][1])

    int a[21][21];
    memset(a, 0, sizeof(a));
    a[20][10]=1;
    for(int i=19; i>=1; i--){
        for(int j=0; j<=10; j++){
            a[i][j] = a[i+1][j]*3 + a[i+1][j+2];
        }
    }
    cout<<a[1][0]<<":"<<a[1][1]<<endl;

还有一种方法: 白球的数量每轮减少0 或2, 所以白球数量始终是偶数,如果只剩一个球,则必定是黑球。


7 蚂蚁爬杆

找所有蚂蚁都离开杆子的最短和最长时间。呵呵,简单转化一下就变成同时求最大最小值了。


8 取石子游戏数学推导


9 24 点

带状态压缩(二进制,表示第几个数被用到)的dp

s[ bits ] = map< result, cnt > // bits 表示哪些数字被用到, result表示计算结果, cnt表示得到该结果的方法数

inline int calc(int tt, int a, int op, int b, bool & tag){
    if(tt) {int tmp =a; a=b; b=tmp;}
    switch(op){
        case 0: return a-b;
        case 1: return a+b;
        case 2: return a*b;
        case 3:{
                   if(b==0) {tag=false; return 0;}
                   return a/b;
               }
    }
    tag= false; return 0;
}

bool 24Game(vector<int> &num){
    vector<map<int, int> > s(16, map<int, int>());
    for(int i = 0; i<4; i++)
        s[1<<i] [num[i]] = 1;

    for(int i= 1; i<16; i++){
        for(int j = 1; j<i; j++){
            if( i & j != i ) continue;
            // merge : f(j) U f(i-j) => f(i), 
            for(map<int, int>::iterator it = s[j].begin(); it != s[j].end(); it++){
                for(map<int, int>::iterator jt = s[i - j].begin(); jt != s[i-j].end(); jt++){
                    for(int op = 0; op<4; op ++ ){
                        for(int tt =0; tt<2; tt++){
                            bool tag = true;
                            int res = calc(tt, it->first, op, jt->first, tag);
                            if(tag){// record the result
                                s[i][res] = s[i][res] + (it->second*jt->second);
                            }
                        }
                    }
                }
            }
        }
    }
    return s[15][24] > 0;
}

10 数字哑谜和回文

哑谜: 数学推理

回文: 枚举“我”和寺,很快能够 找到人过大佛四*我 = 是佛。的所有解

he^2 = she, 类似, (10*h +e )^2 = h^2*100 + e^2 + 20*h*e = s*100 + 10*h + e, 则 e^2 %10 = e, e = 1、5、6、0

e = 1:    1 + 20h + 100h^2 = 1 + 10h + 100s, 10h = 100(s-h^2), h = 10(s-h^2), s=h^2, h=0, s=0 不行

e = 5....


======================================================

10 俄罗斯方块

二进制表示块


11 扫雷


12 数独


13 饮料供货

方法一: dp  

value[ volume ] [ obj_i ] 表示对obj_i饮料物品分组进行装包,得到的最大满意度

value[ volume ] [ obj_i ] = max ( value[volume - k* w[i] ] [ obj_i - 1] + v[i] * k, k = 0 ~ C[i] ) 即对重量为volume状态,轮番使用分组中的物品

for i = 1 to n://分组

      for volume=max_volume to k*w[i]://每个重量

            for k = 1 to C[i]://每个分组物品

                value[ volume ] [ obj_i ] = max ( value[volume - k* w[i] ] [ obj_i - 1] + v[i] * k //上一个分组递推到本分组

或者:

for i = 1 to n://分组

     for k = 1 to C[i]://每个分组物品

            for volume=max_volume to k*w[i]://每个重量

                value[ volume ] [ obj_i ] = max ( value[volume - k* w[i] ] [ obj_i - 1] + v[i] * k


方法二:记忆化搜索(dfs+dp)

一些不需要用到的状态就不用算了


方法三: 贪心法

考虑到 max_volume 是一个二进制的数, 那么每次从最低位找,找到可以用于填充这一位的饮料 

比如第 j(j>=0)位, 对应于可以用的饮料为 ( w=2^k,  value=xx ),其中k<=j

根据贪心策略找到最好的、这一位可用的饮料。使用 2^(j-k)单位 。


14 光影切割问题

根据交点个数,能够推导直线分割的面数, 即cnt(0)=1, cnt (n) = cnt(n-k) + k+1 , cnt(n) = E(ki) + n=交点个数+n+1

所以O(n^2) 枚举获得所有交点。O(mlogm)为对交点排序。


另外,可以使用逆序对个数来算交点

如直线跟两边的边框纵线相交,如线1在两条边框上交点分别为(y1=1, y2=10),而另一个线为(y1=10, y2=1),那么他们有一个逆序对,也必有一个交点。


15 买书问题

这道题直觉上可以greedy,但其实不行,必须states dynamic planning

cnt[y1][y2][y3][y4][y5] 表示各种书分别为y1,y2..y5,其中y1>=y2>=y3>=y4>=y5,的最大折扣数

这个dp存在一个优化:

对任意状态cnt[y1][y2][y3][y4][y5] ,后续除了<[1,2,3],4,5>一定存在<[1 2 3] 4>这种含有4而不含5的放书方法, 

同理后续除了<[1,2],3,4>一定存在<[1,2] 3>这种含有3不含4的方法

所以递推公式变得简单了:cnt[y1][y2][y3][y4][y5]  = max( cnt[y1-1][y2-1][y3-1][y4-1][y5-1]  if(y5>=1),  cnt[y1-1][y2-1][y3-1][y4-1][y5]  if(y4>=1),  cnt[y1-1][y2-1][y3-1][y4][y5] if(y3>=1)。。。, cnt[y1-1][y2][y3][y4][y5] if(y1>=1) ). 

 ====================================

第一章:

1  绘制cpu占用率曲线


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值