Python

秋招记录-知乎

2018-08-19  本文已影响373人  文哥的学习日记

知乎连续面了三面,第三面挂了,不过还是学习到了不少的东西。

一面:
1、介绍项目
2、一个数组,所有数组都出现了两次,只有一个数出现了一次,返回这个数
这个题很简单,两个相同的数的异或是0,因此所有数求异或,剩下的数即为我们要求的数。

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for(int i=0;i<nums.length;i++)
            res ^= nums[I];
        return res;
    }
}

3、一个数组,一个数出现了超过一半次数,返回这个数
这里用到的就是两两消除的思路。

class Solution {
    public int majorityElement(int[] nums) {
        if(nums==null || nums.length==0)
            return -1;
        int res = nums[0];
        int count = 1;
        for(int i=1;i<nums.length;i++){
            if(res == nums[I])
                count++;
            else{
                if(count==0){
                    count ++;
                    res = nums[I];
                }
                else
                    count--;
            }
        }
        return res;
    }
}

4、将除法的结果用字符串返回,如果能够除尽,则返回相除的结果,如果不能除尽,则无限循环部分用[]标记。
这里我采用了队列和Map的做法,使用map记录每个除数出现的位置,如果出现了相同的除数,则表明出现了无限循环部分。如果除数变成了0,则说明除尽了。

import java.util.*;
public class DivideTwoInteger {

    public static void divide(int p1,int p2){
        Queue<Integer> queue = new LinkedList<Integer>();
        int intPart = p1 / p2;
        int reminder = p1 % p2;
        if(reminder == 0){
            System.out.println("" + intPart);
            return;
        }

        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        map.put(reminder,0);
        int index = 0;
        while(true){
            queue.offer(reminder * 10 / p2);
            reminder = reminder * 10 % p2;
            if(map.containsKey(reminder) || reminder==0)
                break;
            else
                map.put(reminder,++index);
        }
        StringBuilder stb = new StringBuilder();
        stb.append(intPart + "");
        stb.append(".");
        if(reminder == 0){
            while(!queue.isEmpty())
                stb.append(queue.poll() + "");
            System.out.println(stb.toString());
        }
        else{
            int pos = map.get(reminder);
            index = 0;
            while(index < pos)
                stb.append(queue.poll() + "");
            stb.append("[");
            while(!queue.isEmpty())
                stb.append(queue.poll() + "");
            stb.append("]");
            System.out.println(stb.toString());
        }
    }
    public static void main(String[] args){
        divide(1,3);
        divide(100,3);
        divide(6,3);
        divide(10,4);
    }
}

5、介绍下DeepFM

二面:
1、介绍项目
2、word2vec的原理简单介绍下
有关word2vec的原理,大家可以看https://blog.csdn.net/itplus/article/details/37969519
3、DeepFM介绍下
4、FM推导

5、数组排序,假设数组排序后的位次和排序前的位次绝对值差值小于K,有什么比快排好的算法?
堆排序,建堆的过程是KlogK。我开始说用堆排序,先将数组的前K+1个元素建堆,然后每次出去一个进来一个,完成排序。面试官问我,这样做是有序的么。我一开始说不一定,但仔细想想,一定是有序的。我们来分析一下。
因为排序前和排序后,同一个数字的索引之差小于等于K。假设K=3,也就是说,索引为2的数,在排序后,最大位置不超过5。再假设我们当前找到的是排序后索引为2的数,且后面有一个数比这个要小。由于这个数不在堆中,因此这个数的排序前索引一定大于5,这与假设相矛盾。因此用堆排序一定能保证数组有序。

6、树中两个节点的第一个的公共祖先。
这个题Leetcode上有原题:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/
代码贴出来:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null || root == p || root== q)
            return root;
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left!=null && right!=null) return root;
        return left !=null?left:right!=null?right:null;
    }
}

三面:
1、介绍下项目
2、word2vec里面的层次索引
3、boosting和bagging的区别?
1)样本选择上:
Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的.
Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化.而权值是根据上一轮的分类结果进行调整.
2)样例权重:
Bagging:使用均匀取样,每个样例的权重相等
Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大.
3)预测函数:
Bagging:所有预测函数的权重相等.
Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重.
4)并行计算:
Bagging:各个预测函数可以并行生成
Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果.

4、bagging为什么能减小方差?
参考博客:https://blog.csdn.net/shenxiaoming77/article/details/53894973

可能不懂的地方看下面的公式就知道了:

5、交叉熵损失函数,0-1分类的交叉熵损失函数的。什么是凸函数?0-1分类如果用平方损失为什么用交叉熵而不是平方损失?
这里我们只回答最后一个问题,也就是说逻辑回归为什么不用平方损失?有两点原因:
1)平方损失函数非凸函数。为什么非凸?凸函数二阶导数大于等于0,证明一下即可。
2)但是会在h(wx)接近0和1的地方梯度很小,不容易学习。

6、python里的gc和多线程。
在Python中,为了解决内存泄露问题,采用了对象引用计数,并基于引用计数实现自动垃圾回收。

上一篇 下一篇

猜你喜欢

热点阅读