牛客_美团点评2020校招前端笔试题(仅个人学习记录)

1.(问答题)
题目描述

class A { 
	String i = "op"; 
	void func(String s) { 
		s = ""+9; 
	} 
	static void test() { 
		A a = new A();   
		a.func(a.i); 
	} 
} 

问:

  1. 变量i,s,a在堆还是在栈中?
  2. 第8行执行完后a.i的值是什么?

1、i,s,a都在栈中,new出来的对象A在堆上。
考察js堆与栈:
栈内存主要用于存储各种基本类型的变量,包括Boolean、Number、String、Undefined、Null以及对象变量的指针;堆主要存储new出来的对象。
所以字符串变量i,s以及对象指针a都存在栈中,new出来的对象开辟内存存在堆上,对应地址是指针a存的内容
2、执行完后a.i的值还是字符串op。
考察参数传递按值传递:a是A类的实例,所以a.i=‘op’,a.func(a.i)这句执行函数,把a.i作为参数传递,该函数会复制一个变量,两个变量完全独立,所以在函数体里只是把复制的那个变量(一个新的局部变量)改变为’op9’,在函数体外的a.i并没有被改变
另外补充说明ECMAScript中所有函数的参数都是按值传递的——《高程3》,其实对于参数是对象的情况,实际上也是按值传递,把传参的指针复制出一个完全独立的变量,只是存的内容和传参对象地址一摸一样
JS中函数参数值传递和引用传递

2.(问答题)
请按顺序写出打印结果,并说明原因。

var name = 'global'; 
var obj = {     
	name: 'local',     
	foo: function(){         
		this.name = 'foo';     
	}.bind(window) 
};
var bar = new obj.foo(); 
setTimeout(function() {     
	console.log(window.name); 
}, 0); 
console.log(bar.name);   

var bar3 = bar2 = bar; 
bar2.name = 'foo2'; 
console.log(bar3.name);

第10行的console是在定时器函数中,因此最后执行。
首先输出第12行bar调用name,由于第8行var bar = new obj.foo(); new绑定的优先级大于bind绑定,所以函数内部this还是obj {},输出foo。
再输出第16行console.log(bar3.name),bar3=bar2=bar,bar3/bar2/bar都是指向同一个对象,因此输出bar中的foo2。
最后输出定时器里的window.name,即global。

参考JS的this问题;JS this指向总结
哪个对象调用函数,函数里面的this指向哪个对象。
this 主要是在函数中使用,在函数外使用,一律指向全局对象。
在函数内使用 this 时,具体指向是由函数的调用方式决定,而不是根据函数定义方式决定。

  1. 函数作为普通函数运行时,可以看做是当做全局对象的方法运行,此时 this 指向全局对象
  2. 函数作为对象的方法调用时,函数内的 this 指向该对象
  3. apply call bind 改变 this 指向,bind 不会受到 apply 和 call 影响,bind优先级最高。一旦经历过bind函数,后面全输出bind指向的值。
  4. 定时器setTimeout设置的函数,this 会指向全局。bind 强制绑定优先级最高,不受定时器影响。
  5. ES6 箭头函数
    ES6 的箭头函数没有自己的 this 和 arguments, 因此在箭头函数内部使用 this 和 argments, 其实使用的是外层的 this 和 arguments。由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。优先级高于bind

3.(问答题)
题目描述
请写出如下代码运行后产生的结果,并给出解释,说明结果是如何得出的。

setTimeout(() => console.log('a'));
Promise.resolve().then(
   () => console.log('b’);
 ).then(
   () => Promise.resolve('c').then(
     (data) => {
       setTimeout(() => console.log('d'));
       console.log('f');
       return data;
     }
   )
 ).then(data => console.log(data));

b f c a d 解析戳此

JS的setTimeout和Promise——同步异步和微任务宏任务
这一次,彻底弄懂 JavaScript 执行机制(这一篇我看的最明白,)

macro-task(宏任务):包括整体代码script,setTimeout,setInterval
micro-task(微任务):Promise,process.nextTick
不同类型的任务会进入对应的Event Queue,比如 setTimeout 和 setInterval 会进入相同的Event Queue。
事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。
一般看到单独的console.log(),new Promise()都是直接输出,把then, process.nextTick扔到微任务的队列里等待按序执行,把setTimeout扔到宏任务的队列里等待按序执行。

延伸题:

console.log('1'); 
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

过程:

console.log('1'); %直接输出毫无疑问 1;至此输出1
setTimeout(function() { %setTimeout放到宏队列_1,暂不输出,标记为setTimeout1;
process.nextTick(function() {%process.nextTick放到微队列_1,暂不输出,标记为process1;
new Promise(function(resolve) {%new Promise毫无疑问,直接输出7;至此输出1 7
}).then(function() {%then放到微队列_2,标记为then1;
setTimeout(function() {%放到宏队列_2,标记为setTimeout2;
至此一遍循环结束,开始执行微队列:
微队列_1:process1,输出6;至此输出1 7 6
微队列_2:then1,输出8;至此输出1 7 6 8,微队列全部输出完毕,开始宏队列
宏队列_1:setTimeout1, console.log('2');直接输出2;至此输出1 7 6 8 2
process.nextTick放到微队列_3,标记为process2
new Promise(function(resolve) {%直接输出4,至此输出1 7 6 8 2 4
}).then(function() {%放到微队列_4,标记为then2
至此宏队列_1循环一遍,把微队列里的值按序输出,即process2,then2,至此输出1 7 6 8 2 4 3 5 
宏队列_2同上,最终输出结果:1 7 6 8 2 4 3 5 9 11 10 12

4.请写出下面ES6代码编译后所生成的ES5代码;

class Person {
     constructor (name) {
          this.name = name;
     }
     greet () {
          console.log(`Hi, my name is ${this.name}`);
     }
     greetDelay (time) {
          setTimeout(() => {
               console.log(`Hi, my name is ${this.name}`);
          }, time);
     }
}
 var Person = (function () {
     function Person (name) {
          this._name = name;
     }
     Person.prototype.greet = function () {
          console.log(“Hi, my name is “ + this._name);
     }
     Person.prototype.greetDelay = function (time) {
          var _this = this;
          setTimeout(function () {
               console.log(“Hi, my name is “ + _this.name);
          }, time);
     }
})();

编程题都是动态规划题,动态规划的核心在于将整体问题分解成局部问题进行求解。
5.形如1, 1, 2, 3, 5, 8, 13, 21, 34, 55的数列,后一位是前面两位相加(斐波那契数列),写出函数要求找到第 N 位是多少,如:fib(3) => 3 , fib(5) => 8, 要求时间复杂度为O(n)。

let num = readline()
function fabonacci(num){
    if(num === 0 ||num === 1 ) return 1
    let res = [1,1,2]
    for(let i = 3 ;i<=num ;i++){
        res[i] = res[i-1] + res[i-2]
    }
    return res[num]
 }
console.log(fabonacci(num))
function fib(n){
    let top=1,bottom=0,res=0
    for(let i=0;i<n;i++){
        res=top+bottom
        bottom=top
        top=res
    }
    return res
}
#include 
using namespace std;
long long feb(int n)
{
    long long a=1,b=1,c=1;
    int i;
    for (i=0;i<n-1;i++)
    {
        c=a+b;
        a=b;
        b=c;
    }
    return c;
}

int main()
{
    int n;
    cin>>n;
    cout<<feb(n)<<endl;
    return 0;
}

6. 最少硬币问题
根据题意找到动态方程dp[i] = Math.mix(dp[i-coin] +1,dp[i])

近期某商场由于周年庆,开启了“0元购”活动。活动中,消费者可以通过组合手中的代金券,实现0元购买指定商品。**

聪明的小团想要用算法来帮助他快速计算:对于指定价格的商品,使用代金券凑出其价格即可,但所使用的代金券总面额不可超过商品价格。由于代金券数量有限,使用较少的代金券张数则可以实现价值最大化,即最佳优惠。

假设现有100元的商品,而代金券有50元、30元、20元、5元四种,则最佳优惠是两张50元面额的代金券;而如果现有65元的商品,则最佳优惠是两张30元代金券以及一张5元代金券。

请你帮助小团使用一段代码来实现代金券计算。

输入描述:
多组输入输出,读到s=0时结束
输入可以有多个测试样例,每个测试由两行组成。
其中第一行包含一个整数P,表示商品的价格,1≤P≤10000;输入P为0时表示结束。

第二行包含若干整数,使用空格分割。其中第一个整数N(1≤N≤20)表示有多少种代金券,其后跟随M个整数,表示手中持有的代金券面额(1≤N≤1000),每种代金券数量不限。

输出描述:
找到最少张数的代金券,使其面额恰好等于商品价格。输出所使用的代金券数量;

如果有多个最优解,只输出其中一种即可;

如果无解,则需输出“Impossible”。

示例1
输入
65
4 50 30 20 5
0
输出
3

链接:https://www.nowcoder.com/questionTerminal/5d2405da8d364eafbaca1de9bc2a0d4e
来源:牛客网

while(true){
    let nums = parseInt(readline())
    if(nums === 0 ) break
    let coins = readline().split(" ").map(Number).slice(1)
    console.log(fn(coins,nums))
}
function fn(coins,nums){
    let dp = new Array(nums+1).fill(Infinity)
    dp[0] = 0
    for(let i = 1;i<=nums;i++){
        for(let coin of coins){
            if( i >= coin ){
                dp[i] = Math.min(dp[i],dp[i-coin]+1)
            }
        }
    }
    return dp[nums] === Infinity ? 'Impossible' : dp[nums]
}

链接:https://www.nowcoder.com/questionTerminal/5d2405da8d364eafbaca1de9bc2a0d4e
来源:牛客网

#include 
using namespace std;
  
int main(){
    int flag=1;
    while(flag){
        int cash;
        cin>>cash;
        if(cash==0){
            break;
        }
        int num;
        cin>>num;
        int *coins=new int[num];
        int count=0;
        int size=num;
        while(num--){
            cin>>coins[count];
            count++;
        }
        for(int p=0;p<size;++p){
            for(int q=0;q<size-p-1;++q){
                if(coins[q]>coins[q+1]){
                    swap(coins[q],coins[q+1]);
                }
            }
        }
        int *F=new int[cash+1];
        for(int i=0;i<=cash;++i){
            F[i]=cash+1;
        }
        F[0]=0;
        for(int j=0;j<=cash;++j){
            for(int k=0;k<size;++k){
                if(j<coins[k]){
                    break;
                }
                else{
                    F[j]=min(F[j-coins[k]]+1,F[j]);
                }
            }
        }
        if(F[cash]==cash+1){
            cout<<"Impossible"<<endl;
        }
        else{
            cout<<F[cash]<<endl;
        }
    }
}

7.关键还是动态方程dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grid[i][j]
leetcode原题

给定一个包含非负整数的 M x N 迷宫,请找出一条从左上角到右下角的路径,使得路径上的数字总和最小。每次只能向下或者向右移动一步。**

小团在一次星际旅行中,耗尽了飞船的能量,迷失在了空间魔方中,空间魔方中有NNN个能量粒子。美团云AI迅速帮小团分析出了空间魔方的能量分布图。

已知小团的飞船被困在能量值最高的点,能量值最高点有且只有一个。飞船每到达一个能量粒子就会吸收对应粒子的能量,该粒子会坍缩成小黑洞,飞船不可到达。小团驾驶的飞船只能从高能粒子驶向低能粒子,且每次只能从6个方向中选择一个前进。(±x,±y,±z)。
请帮助帮小团吸收最高的能量值。

链接:https://www.nowcoder.com/test/question/done?tid=31652586&qid=894519#summary

let array = readline().split(" ").map(Number)
let row = array[0],col = array[1]
let grid = []
while(line = readline()){
    grid.push(line.split(" ").map(Number))
}
function fn(row,col,grid){
    let martix = Array.from(new Array(row),()=>new Array(col))
    for(let i = 0;i < row;i++){
        for(let j = 0;j < col;j++){
            if(i === 0 && j ===0 ){
                martix[i][j] = grid[i][j]
            }else if(i === 0 && j > 0){
                martix[i][j] = martix[i][j-1] + grid[i][j]
            }else if(i > 0 && j === 0){
                martix[i][j] = martix[i-1][j] + grid[i][j]
            }else{
                martix[i][j] = Math.min(martix[i][j-1],martix[i-1][j])
                                        + grid[i][j]
            }
        }
    }
    return martix[row-1][col-1]
}
console.log(fn(row,col,grid))

你可能感兴趣的:(牛客_美团点评2020校招前端笔试题(仅个人学习记录))