Categories
生活琐碎

16年网易数据挖掘实习生笔试小记

恩,不透题,只写个大概~
 
形式:在线笔试,两个小时。
题量:10个单选,10个不定项选择,5个大题(2个编程题+3个其他题)
期间网页不能切出去(据说有切出去5次被禁止作答的),实时摄像头监控。
 
客观题里有印象的考点:

  • 树的遍历(前序、中序、后序)
  • linux基本指令
  • Hadoop/Spark基础
  • 数据库基础
  • C++指针、数组、常用算法的概念(KMP)
  • 聚类方法、降维方法(主要是概念)

主观题:

  • 编程题1:小数的四舍五入
  • 编程题2:给定树的BFS序列和目标target,输出某路径上的节点值相加等于target的
  • 主观题1:机器学习(神经网络)的概念
  • 主观题2:概率图模型推导
  • 主观题3:loss function相关,梯度算子推导(似乎是这个)

整体感觉难度很有区分性,选择题考概念基础,编程题难度不是很大,三个主观题倒是不大会,自己估计是要当大分母了!

Categories
不学无术

LeetCode 230. Kth Smallest Element in a BST

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note:
You may assume k is always valid, 1 ≤ k ≤ BST’s total elements.
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?

思路:

二叉搜索树的中序遍历(LNR)就是按照从小到大顺序排的,所以遍历到N节点的时候就记个数,计数到k的时候就返回了。

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int kthSmallest(TreeNode* root, int k) {
        if(root == NULL)
            return -1;
        int retVal = -1;
        int count = 0;
        kthSmallest1(root, k, count, retVal);
        return retVal;
    }
    void kthSmallest1(TreeNode* root, int k, int& count, int& retVal){
        if(count >= k)
            return;
        if(root->left != NULL)
            kthSmallest1(root->left, k, count, retVal);
        count ++;
        if(count == k){
            retVal = root->val;
            return;
        }
        if(root->right != NULL)
            kthSmallest1(root->right, k, count, retVal);
    }
};

 

Categories
木有技术

LeetCode 203. Remove Linked List Elements

Remove all elements from a linked list of integers that have value val.
Example
Given: 1 –> 2 –> 6 –> 3 –> 4 –> 5 –> 6, val = 6
Return: 1 –> 2 –> 3 –> 4 –> 5

思路:

思路很简单,记录当前指针的前一个节点,然后val对上的话把前一个节点的next指针指向当前节点的next指针。有几个需要注意的输入:

  1. 空指针输入,即head就是NULL
  2. head->val等于val的情况,即删除完后head指针会变化
  3. 末尾节点要删除的情况
  4. 删完之后链表变空的情况

《剑指Offer》这书还挺有用的,代码的稳健性很重要。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        if(head == NULL)
            return head;
        ListNode* pNewHead = head;
        ListNode* pPrev = NULL;
        ListNode* pCurr = head;
        while(pCurr != NULL){
            if(pCurr->val == val){
                if(pPrev == NULL) {//pCurr is the head of linkedlist
                    pNewHead = pCurr->next;
                } else {
                    pPrev->next = pCurr->next;
                }
            } else {
                pPrev = pCurr;
            }
            pCurr = pCurr->next;
        }
        return pNewHead;
    }
};

 

Categories
不学无术

LeetCode 26. Remove Duplicates from Sorted Array

Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this in place with constant memory.
For example,
Given input array nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn’t matter what you leave beyond the new length.

思路

倆指针~一个指向当前实际有效的位置,一个指向当前处理的位置
题外话:经历感冒鼻塞喉咙痛快一周,脑子终于是清楚了!

代码

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int numSz = nums.size();
        if(numSz <= 1)
            return numSz;
        int i=0;
        int j=1;
        while(j < numSz){
            if(nums[j] == nums[i])
                j++;
            else {
                nums[++i] = nums[j];
                j++;
            }
        }
        return i+1;
    }
};

 

Categories
不学无术

LeetCode 53. Maximum Subarray

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray [4,−1,2,1] has the largest sum = 6.

思路

这个是剑指Offer还是什么程序员面试经典或者是编程珠玑上的一道题,反正已经广为流传了。
O(n)复杂度的想法是,假定我有之前能得到的最大和子串的和sum[i-1]和当前值a[i],如何得到当前的最大和sum[i]呢?分两个情况:

  • 如果sum[i-1]+a[i]<a[i],比如上面那个数列的前两项-2+1 = -1 < 1,那意思就是前面那么好的加起来还不如从我这边重新开始来的好,则sum[1]就是a[i]
  • 否则,更新sum[i]=sum[i-1]+a[i]

概括成一句话就是,既然之前的人加在一起都不如我,那就我带头上吧!

代码

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.empty())
            return -1;
        int max = nums[0];
        for(int i = 1; i<nums.size(); i++){
            if(nums[i-1] + nums[i] > nums[i]){
                nums[i] += nums[i-1];
            }
            if(nums[i] > max)
                max = nums[i];
        }
        return max;
    }
};

 

Categories
不学无术

LeetCode 88. Merge Sorted Array

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 andnums2 are m and n respectively.
代码:

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        for(int i=0; i<n; i++) {
            // /!\ Mind that m might be less than the actual size of nums1
            if(nums1.size() < m + i + 1)
                nums1.push_back(-1);
        }
        int pos_1 = m-1;
        int pos_2 = n-1;
        int end = m + n - 1;
        while(pos_1 >= 0 && pos_2 >= 0) {
            if(nums1[pos_1] > nums2[pos_2]) {
                nums1[end] = nums1[pos_1];
                pos_1--;
            } else {
                nums1[end] = nums2[pos_2];
                pos_2--;
            }
            end--;
        }
        while(pos_2 >= 0){
            nums1[end--] = nums2[pos_2--];
        }
    }
};

 

Categories
不学无术

LeetCode 70. Climbing Stairs

题目: https://leetcode.com/problems/climbing-stairs/
思路:
递归递归,但是跟斐波那契数那个一样,要保存一些中间算出来的结果备用,不然会超时!
代码:

class Solution {
public:
    map<int, int> resultMap;
    int climbStairs(int n) {
        if(n == 2){
            // 2 or 1+1, two ways
            return 2;
        } else if(n == 1) {
            return 1;
        } else if (n == 0) {
            return 0;
        } else {
            int c_n1, c_n2;
            if(resultMap.count(n-1) > 0)
                c_n1 = resultMap[n-1];
            else {
                c_n1 = climbStairs(n-1);
                resultMap[n-1] = c_n1;
            }
            if(resultMap.count(n-2) > 0)
                c_n2 = resultMap[n-2];
            else {
                c_n2 = climbStairs(n-2);
                resultMap[n-2] = c_n2;
            }
            return c_n1 + c_n2;
        }
    }
};

 

Categories
不学无术

LeetCode 215. Kth Largest Element in an Array

题目:https://leetcode.com/problems/kth-largest-element-in-an-array/
思路:
找第k大的元素,最简单的方法就是排个序,然后找一下(中位数其实也类似),时间复杂度是O(nlogn)
另一种方案是,参考快速排序的方法找个pivot,然后分三种情况:

  • pivot的位置刚好就是第k大的,那么大功告成;
  • pivot的位置在k前头,那么就得找pivot后面一堆了;
  • pivot的位置在k后头,那么得找pivot前面的一堆;

代码:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        return findKthLargest1(nums, 0, nums.size()-1, k);
    }
    int findKthLargest1(vector<int>& nums, int start, int end, int k) {
        int small = start;
        int large = end;
        int pivot = nums[large];
        while(true){
            while(nums[small] > pivot && small < large)
                small ++;
            while(nums[large] <=pivot && small < large)
                large --;
            if(small == large)
                break;
            swap(nums, small, large);
        }
        swap(nums, small, end);
        if(small == k - 1){
            return pivot;
        } else if (small > k - 1) {
            return findKthLargest1(nums, start, small - 1, k);
        } else {
            return findKthLargest1(nums, small + 1, end, k);
        }
    }
    void swap(vector<int>& nums, int small, int large) {
        int temp = nums[small];
        nums[small] = nums[large];
        nums[large] = temp;
    }
};

 

Categories
不学无术

LeetCode 208. Implement Trie (Prefix Tree)

题目:https://leetcode.com/problems/implement-trie-prefix-tree/
思路:
前缀树的概念,参考这里。谷歌搜到的,其实有一大把~
判断是否有这么个“儿子”的时候,增加了一个hasEnd布尔值,如果有以这个点为结束的字符则设置成true.
限制:为了实现方便,现在只能存储a-z共26个字符,如果再扩展可以考虑用map来存字符对应的孩子指针。
单词的字符数量为M,插入节点的时间复杂度是O(M)
startWith(..)和search(..)一大半部分可以合并
代码:

class TrieNode {
public:
	bool hasEnd;
	TrieNode** children;
	// Initialize your data structure here.
	TrieNode() {
		children = NULL;
		hasEnd = false;
	}
	bool hasChild(char c) {
		if (NULL == children)
			return false;
		return !(NULL == children[c - 'a']);
	}
	TrieNode* addChild(char c) {
		if (NULL == children) {
			children = new TrieNode*[26];
			for (int i = 0; i<26; i++)
				children[i] = NULL;
		}
		int pos = c - 'a';
		children[pos] = new TrieNode;
		return children[pos];
	}
};
class Trie {
public:
	Trie() {
		root = new TrieNode();
	}
	// Inserts a word into the trie.
	void insert(string word) {
		int wordSz = word.size();
		char c;
		TrieNode *currNode = root;
		for (int i = 0; i<wordSz; i++) {
			c = word[i];
			if (currNode->hasChild(c))
				currNode = currNode->children[c - 'a'];
			else {
				currNode = currNode->addChild(c);
			}
			if (i == wordSz - 1)
				currNode->hasEnd = true;
		}
	}
	// Returns if the word is in the trie.
	bool search(string word) {
		int wordSz = word.size();
		char c;
		TrieNode *currNode = root;
		for (int i = 0; i<wordSz; i++) {
			c = word[i];
			if (currNode->hasChild(c))
				currNode = currNode->children[c - 'a'];
			else
				return false;
		}
		return currNode->hasEnd;
	}
	// Returns if there is any word in the trie
	// that starts with the given prefix.
	bool startsWith(string prefix) {
		int wordSz = prefix.size();
		char c;
		TrieNode *currNode = root;
		for (int i = 0; i<wordSz; i++) {
			c = prefix[i];
			if (currNode->hasChild(c))
				currNode = currNode->children[c - 'a'];
			else
				return false;
		}
		return true;
	}
private:
	TrieNode* root;
};
// Your Trie object will be instantiated and called as such:
// Trie trie;
// trie.insert("somestring");
// trie.search("key");

 

Categories
不学无术

LeetCode 34. Search for a Range

题目:https://leetcode.com/problems/search-for-a-range/
思路:看LogN级别时间复杂度的要求就应该可以想到要用二分查找类似的做,关键问题是有重复元素,就是说如果找到了a[i]==target,还得顾及一下他的左右邻居的值是不是也一样的,如果是的话,那说明还得继续找
代码:

class Solution {
public:
    int searchMin(vector<int>& nums, int target) {
        int l = 0;
        int r = nums.size() - 1;
        int m;
        while (l <= r) {
            m = (l + r)/2;
            if(nums[m] == target){
                if(m == 0)
                    return m;
                else if(nums[m-1] < target) //targst cannot be in the left part
                    return m;
                else {
                    r = m - 1;
                }
            } else if(nums[m] < target) {
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return -1;
    }
    int searchMax(vector<int>& nums, int target) {
        int l=0;
        int r = nums.size() - 1;
        int m;
        while(l <= r) {
            m = (l + r)/2;
            if(nums[m] == target){
                if (m == r)
                    return m;
                else if(nums[m+1] > target)
                    return m;
                else
                    l = m + 1;
            } else if (nums[m] < target) {
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return -1;
    }
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> result;
        result.push_back(searchMin(nums, target));
        result.push_back(searchMax(nums, target));
        return result;
    }
};