2019苏州微软面经
简介,苏州微软,目前已经电话三轮,全过,过了后可以公费去苏州现场面试。
比国外 Google的面试难度要低一些,或者说,偏重点更不一样。
微软你可以只做一道面试题,思路清晰,完整,边界情况考虑清楚,代码写好就行了。
但是 Google 是需要你在 40 分钟内,完美答出两道题目,这就是区别。
另外,苏州微软是用中文的,也是容易了一些的原因——因为用英语你确实脑子转不过来。
第一轮
没有给出题目,口头说的,我整理一下:
判断一个数组是否基本有序,其实就是可否通过一次简单的交换就满足有序。
例子:
-
1, 2, 3, 6, 5, 12
是基本有序数组,因为可以交换 6 跟 5, 变成1, 2, 3, 5, 6, 12
-
1, 5, 4, 3, 6
也是基本有序数组,可以交换 5 跟 3 -
3,2, 1, 0
就不是基本有序数组了,因为你交换一次数组并不能使此数组有序。
思路不难,仔细分析一下,有序的数组数字关系是这样: a < b < c < d < e
,而基本有序则是:a < b > c > d <e
,这样可能不好看,简单来说就是那两个数字在是不满足x < y
的关系的。
可以遍历此数组,只要有多于一个数字是比两边都要大,且有一个数字是比左右两边要小的,那就是基本有序数组,其余的都不是。当然,你也要考虑本来这个数组就是有序的情况。
在面试时写的代码与交流草稿如下,这份代码是不能当答案看的,只是让朋友你们看看怎么样的代码可以过面试。建议你们自己写写可以编译过的代码。
int array
1, 2, 3, 6, 5, 12 true
i
min: 3, miax: 5
1, 5, 4, 3, 6
sub array -> reverse -> true
1, 2, 3, 6, _5,
1, 5, 4, 3, 6
max: 5
min: 3
1 < min < max < least
i,
1, 5, 4, 2, 8, 19, 7, 12
5, 4, 9
min: 2
max: 5
sub array -> sorted?
7
3
i: 2,
1, 2, 3, 8, 7, 6 ,5, 12
bool is_almost_sorted_array(vector<int> a) {
int mem_l;
bool flag = false;
int l_idx = -1, r_idx = -1;
On(m sub_arry)
for(int i=0; i<a.size()-1; i++) {
// sub array
if(a[i] > a[i+1]) {
int mem_l = i;
int sub_min = a[mem_l];
if(mem_l+1 < a.size())
sub_min = a[mem_l+1];
while(i<a.size() && a[i] > a[i+1]) {
if(flag == true) return false;
i++;
}
/* 1, 2, 7, 4, 5, 6, 3, 8 */
/* i: 3, ->,
* i: 6,
* */
int sub_max = a[i-1];
if(l_idx == -1 && i - mem_l == 1) {//only one
l_idx = i-1;
}else if(r_idx == -1 && i - mem_l == 1) {
r_idx = i;
if(a[r_idx] > a[l_idx-1] && a[r_idx] < a[l_idx+1] &&
a[l_idx] > a[r_idx-1] && (r_idx == a.size() || a[l_idx] < a[r_idx+1]))
flag = true;
else
return false;
}else{
flag = true; //Have Changed Once
if(sub_min <= a[mem_l] || i == a.size() || sub_max >= a[i])
return false;
}
}
}
return true;
}
test case:
1, 2, 3 =>
3, 2, 1 =>
i:0, a[0]>a[1], mem_l:0, sub_min: 2, subm: 3
i:1, sub_min: a[2] vs 3, 1 3
i:2,
1 >= 1, 3 >=
面试反馈就是对 边界情况考虑不周全,可以多加强。(是的,如上的一些判断语句是跟面试官一起过了一遍才加上的)。
第二轮
第二轮面试官是贴了题目,顺道解释了一下,在这里锻炼你们的英语能力,我就不给你们解释了。
Split a string into sub-strings. Each sub-string should be no longer than the given limit. The input string contains English letters and spaces only.
Do not break a word into two sub strings. Remove all spaces in the beginning or end of every sub string.
Extend: append notation such as " (1 of 12)" and strings are not longer than the limit even after the notation.
Length limit: 39. Input: The quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dogThe quick brown fox jumps over a lazy dog
Result should be:
The quick brown fox jumps (1 of 14)
over a lazy dogThe quick (2 of 14)
brown fox jumps over a lazy (3 of 14)
dogThe quick brown fox jumps (4 of 14)
over a lazy dogThe quick (5 of 14)
brown fox jumps over a lazy (6 of 14)
dogThe quick brown fox jumps (7 of 14)
over a lazy dogThe quick (8 of 14)
brown fox jumps over a lazy (9 of 14)
dogThe quick brown fox jumps (10 of 14)
over a lazy dogThe quick (11 of 14)
brown fox jumps over a lazy (12 of 14)
dogThe quick brown fox jumps (13 of 14)
over a lazy dog (14 of 14)
这题我没有正确的思路,因为现在我还没有想出最优解,也没有在网上找到类似的题目,有看过的同学可以分享一下。难点就是,在插入每行附加信息的同时,又不能让这行的字数超出。
我是这样子做的:
每行先不插入信息,先正常的换行,换行完毕后,再递归去插入信息——因为插入信息后会因为行数进位而又需要调整一遍,如 99 变成 100.
我写出的代码如下:
vector<string> split_sub_strings(string input, int limit) {
vector<string> res;
int count = 0;
for(int i=0; i<input.length(); ++i) {
int mem_i = i;
string current_line = "";
while(input[i] != ' ') {
i++;
}
int word_len = i - mem_i;
//可以容纳下个词不
if(res[count].length() + word_len> limit) {
res.push_back(current_line);
count++;
continue;
}else {
current_line += input.splice(mem_i, i);
}
while(input[i] == ' ') {
i++;
}
}
return update_info(res, limit, count);
}
string get_apend_info(int cnt, int sum) {
return "(" + to_string(cnt) + " of " to_string(sum) + ")"
}
string retrieve_back_words(string s) {
st
for(int i=s.length(); s>0; s--) {
}
}
// backwords:
//Len 35 : The quick(1 of 14)
//over a lazy dogThe quick jumps brown fox (2 of 14)
// append back workds
vector<string> update_info(vector<string> list_of_lines, int limit, int sum) {
vector<string> res;
int cnt = 0;
string back_words = "";
for(auto line : list_of_lines) {
string new_line = line + retrieve_back_words(back_words) + get_apend_info(cnt, sum);
if(new_line.length() > limit){
for(int i=line.length(); i>0; i--) {
mem_i = i;
while(line[i] != ' ') {
line--;
}
back_words = back_words + line.splice(mem_i, i) + ' ';
new_line = line.splice(0, i) + get_apend_info(cnt, sum);
if(new_line.length() < limit) {
res.push_back(new_line);
}
}
}
}
if(back_words.length == 0) {
return res;
}else {
sum += 1;
res.push_back(retrieve_back_words(back_words)
return update_info(res, limit, sum);
}
}
第三轮
这轮是纯英语面试,美国的友人早晨 7 点打电话来的,对于 9 点起床的我来说,状态不好。
leetcode 原题 https://leetcode.com/problems/min-stack/ ,不过我没有做过。
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
- push(x) -- Push element x onto stack.
- pop() -- Removes the element on top of the stack.
- top() -- Get the top element.
- getMin() -- Retrieve the minimum element in the stack.
Example:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> Returns -3.
minStack.pop();
minStack.top(); --> Returns 0.
minStack.getMin(); --> Returns -2.
开始,或者正常人的想法都是马上想到用一个成员变量来存这个最小值,push 的时候能做到 O1,但是做 pop 的时候发现,这时候不清楚 pop 出去的是不是最小值以及是不是有多个最小值,这时算法就不是 O1 了。
想了一下子后,我就想到利用 slice window(滑动窗口)的思想来做,用数组记录区间值最小值,每次 push 不是比这个数小就不存。
例如: 12,6, 9, 7, 5, 22,29, 1
我会这样子存: 12, 6,5,1
。
-
12 无论如何都是要放的,然后 6 比 12 小,存起来;9,7 都不比 6 小,不需要存——之后只要是 9,7 这两个值,返回最小值 6 就行。
-
然后 5 比 6 小,存起来;22,29 大于 5,不需要存,然后最小值就是之前存起来那个 5 啦。
-
最后 1 比 5 小,存起来。
简而言之,就是一个最小值列表,存起来当前区间的最小值。
pop 的时候检查一下最小值数组是否是要 pop 的值,维护一下就行,push 跟 pop 都是 O1 了
做的时候我用的是数组,面试完后我查了下,发现可以用抽象程度更高的 stack 来代替数组。因为我一直处理的也是数组的最后一位,跟 stack 的行为一模一样的。