亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

2020字節(jié)跳動(dòng)前端面試題一面解析(附答案)

  發(fā)布時(shí)間:2020-07-03 17:01:28   作者:前端優(yōu)選   我要評(píng)論
這篇文章主要介紹了2020字節(jié)跳動(dòng)前端面試題一面解析(附答案),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

最近有文章漏出了一位實(shí)習(xí)生面試字節(jié)跳動(dòng)今日頭條的前端面試題,總共四輪面試,現(xiàn)在就跟大家一起來(lái)探討一下這些面試題,為疫情后的工作做些準(zhǔn)備。

1.算法:實(shí)現(xiàn)36進(jìn)制轉(zhuǎn)換

首先新建一個(gè)Stack類,用于定義基本操作方法

class Stack {
    constructor() {
        this.count = 0;
        this.items = {};
    }

    push(element) {
        this.items[this.count] = element;
        this.count++;
    }

    pop() {
        if (this.isEmpty()) {
            return undefined;
        }
        this.count--;
        const result = this.items[this.count];
        delete this.items[this.count];
        return result;
    }

    peek() {
        if (this.isEmpty()) {
            return undefined;
        }
        return this.items[this.count - 1];
    }

    isEmpty() {
        return this.count === 0;
    }

    size() {
        return this.count;
    }

    clear() {
        this.items = {};
        this.count = 0;
    }

    toString() {
        if (this.isEmpty()) {
            return '';
        }
        let objString = `${this.items[0]}`;
        for (let i = 1; i < this.count; i++) {
            objString = `${objString},${this.items[i]}`;
        }
        return objString;
    }
}

然后定義一個(gè)轉(zhuǎn)換方法,用于進(jìn)制轉(zhuǎn)換

function baseConverter(decNumber, base) {
    // 創(chuàng)建 Stack 類
    const remStack = new Stack();
    // 定義一個(gè)進(jìn)制位數(shù),這里設(shè)置了 36 位進(jìn)制,可自定義位數(shù)
    const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    let number = decNumber;
    let rem;
    let baseString = '';

    if (!(base >= 2 && base <= 36)) {
        return '';
    }

    while (number > 0) {
        rem = Math.floor(number % base);
        remStack.push(rem);
        number = Math.floor(number / base);
    }

    while (!remStack.isEmpty()) {
        // 對(duì)棧中的數(shù)字做轉(zhuǎn)化
        baseString += digits[remStack.pop()];
    }

    return baseString;
}

最后進(jìn)行測(cè)試

console.log(baseConverter(1314, 2));    //10100100010
console.log(baseConverter(1314, 8));    //2442
console.log(baseConverter(1314, 16));    //522
console.log(baseConverter(1314, 20));    //35E
console.log(baseConverter(1314, 30));    //1DO
console.log(baseConverter(1314, 35));    //12J

2.簡(jiǎn)述https原理,以及與http的區(qū)別

http請(qǐng)求都是明文傳輸?shù)模@里的明文就是指沒(méi)有經(jīng)過(guò)加密的信息,如果請(qǐng)求被黑客攔截就會(huì)非常危險(xiǎn)。因此Netscape公司制定了https協(xié)議,https可以將傳輸?shù)臄?shù)據(jù)進(jìn)行加密,這樣即使被黑客攔截也無(wú)法破譯,保證了網(wǎng)絡(luò)通信的安全。

https協(xié)議=http協(xié)議+SSL/TLS協(xié)議,需要用SSL/TLS對(duì)數(shù)據(jù)進(jìn)行加密和解密,SSL(Secure Sockets Layer)即安全套接層協(xié)議;TLS(Transport Layer Security)即安全傳輸層協(xié)議,它建立在SSL協(xié)議規(guī)范之上,是SSL的后續(xù)版本。TSL和SSL各自所支持的加密算法不同,但在理解https的過(guò)程中,可以把它們看作是同一種協(xié)議。

HTTPS開(kāi)發(fā)的主要目的,是提供對(duì)網(wǎng)站服務(wù)器的身份認(rèn)證,保護(hù)交換數(shù)據(jù)的隱私與完整性。它其實(shí)就是HTTP+加密+身份認(rèn)證+完整性保護(hù)。

為了兼顧安全與效率,https同時(shí)使用了對(duì)稱加密和非對(duì)稱加密。要傳輸?shù)臄?shù)據(jù)使用了對(duì)稱加密,對(duì)稱加密的過(guò)程需要客戶端一個(gè)秘鑰,為了確保能把該秘鑰安全地傳輸?shù)椒?wù)器端,將該秘鑰進(jìn)行了非對(duì)稱加密傳輸??偨Y(jié)就是:數(shù)據(jù)進(jìn)行了對(duì)稱加密,對(duì)稱加密使用的秘鑰進(jìn)行了非對(duì)稱加密。

客戶端與服務(wù)器建立連接后,各自生成私鑰和公鑰。服務(wù)器返給客戶端一個(gè)公鑰,客戶端拿著公鑰把要傳輸?shù)膬?nèi)容進(jìn)行加密,連同自己的公鑰一起返給服務(wù)器,服務(wù)器用自己的私鑰解密密文,然后把響應(yīng)的數(shù)據(jù)用客戶端公鑰加密,再返給客戶端,客戶端用自己的私鑰解密密文,完成數(shù)據(jù)的展現(xiàn)。

3.操作系統(tǒng)中進(jìn)程和線程怎么通信

進(jìn)程和線程的區(qū)別

進(jìn)程 線程
進(jìn)程是資源分配的最小單位 線程是程序執(zhí)行的最小單位,CPU調(diào)度的最小單位
進(jìn)程有自己獨(dú)立的地址空間 線程共享進(jìn)程的地址空間
進(jìn)程之間的資源是獨(dú)立的 線程共享本進(jìn)程的資源

進(jìn)程和線程通信

進(jìn)程通信 線程通信
管道(包括管道和命名管道) 內(nèi)存中類似于文件的模型,多進(jìn)程可讀寫(xiě) 共享內(nèi)存
消息隊(duì)列 內(nèi)核中的隊(duì)列 管道
共享內(nèi)存  
信號(hào)量  
套接字 不同主機(jī)上的進(jìn)程通信方式  

4.node中cluster是怎樣開(kāi)啟多進(jìn)程的,并且一個(gè)端口可以被多個(gè)進(jìn)程監(jiān)聽(tīng)嗎?

nodejs是單線程的模式,不能充分利用服務(wù)器的多核資源。使用node的cluster模塊可以監(jiān)控應(yīng)用進(jìn)程,退出后重新啟動(dòng)node應(yīng)用進(jìn)程,并可以啟動(dòng)多個(gè)node應(yīng)用進(jìn)程,做到負(fù)載均衡,充分利用資源。

const cluster = require('cluster');
const cpus = require('os').cpus();

const accessLogger = require("../logger").accessLogger();

accessLogger.info('master ' + process.pid + ' is starting.');

cluster.setupMaster({
    /* 應(yīng)用進(jìn)程啟動(dòng)文件 */
    exec: 'bin/www'
});

/* 啟動(dòng)應(yīng)用進(jìn)程個(gè)數(shù)和服務(wù)器CPU核數(shù)一樣 */
for (let i = 0; i < cpus.length; i++) {
    cluster.fork();
}

cluster.on('online', function (worker) {
    /* 進(jìn)程啟動(dòng)成功 */
    accessLogger.info('worker ' + worker.process.pid + ' is online.');
});
cluster.on('exit', function (worker, code, signal) {
    /* 應(yīng)用進(jìn)程退出時(shí),記錄日志并重啟 */
    accessLogger.info('worker ' + worker.process.pid + ' died.');
    cluster.fork();
});
5.實(shí)現(xiàn)原生ajax
通過(guò)XmlHttpRequest對(duì)象向服務(wù)器發(fā)異步請(qǐng)求,從服務(wù)器獲得數(shù)據(jù),然后用 javascript 來(lái)操作DOM更新頁(yè)面的技術(shù)

var xhr = new XMLHttpRequest();
xhr.open("post","http:www.domain.com");
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
xhr.send();
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4 && xhr.status == 200){
        return xhr.responseText;
    }
}

主要考察的是服務(wù)器響應(yīng)的5個(gè)狀態(tài)

0: 請(qǐng)求未初始化(代理被創(chuàng)建,但尚未調(diào)用 open() 方法)
1: 服務(wù)器連接已建立(open方法已經(jīng)被調(diào)用)
2: 請(qǐng)求已接收(send方法已經(jīng)被調(diào)用,并且頭部和狀態(tài)已經(jīng)可獲得)
3: 請(qǐng)求處理中(下載中, responseText 屬性已經(jīng)包含部分?jǐn)?shù)據(jù))
4: 請(qǐng)求已完成,且響應(yīng)已就緒(下載操作已完成)

6.vue-router源碼

這里僅展示關(guān)鍵方法,細(xì)節(jié)處不討論。

先看目錄結(jié)構(gòu)

├─vue-router
│  ├─components # 存放vue-router的兩個(gè)核心組件
│  │  ├─link.js
│  │  └─view.js
│  ├─history    # 存放瀏覽器跳轉(zhuǎn)相關(guān)邏輯
│  │  ├─base.js
│  │  └─hash.js
│  ├─create-matcher.js # 創(chuàng)建匹配器
│  ├─create-route-map.js # 創(chuàng)建路由映射表
│  ├─index.js # 引用時(shí)的入口文件
│  ├─install.js # install方法

編寫(xiě)install方法

export let _Vue;
export default function install(Vue) {
    _Vue = Vue;
    Vue.mixin({ // 給所有組件的生命周期都增加beforeCreate方法
        beforeCreate() {
            if (this.$options.router) { // 如果有router屬性說(shuō)明是根實(shí)例
                this._routerRoot = this; // 將根實(shí)例掛載在_routerRoot屬性上
                this._router = this.$options.router; // 將當(dāng)前router實(shí)例掛載在_router上

                this._router.init(this); // 初始化路由,這里的this指向的是根實(shí)例
            } else { // 父組件渲染后會(huì)渲染子組件
                this._routerRoot = this.$parent && this.$parent._routerRoot;
                // 保證所有子組件都擁有_routerRoot 屬性,指向根實(shí)例
                // 保證所有組件都可以通過(guò) this._routerRoot._router 拿到用戶傳遞進(jìn)來(lái)的路由實(shí)例對(duì)象
            }
        }
    })
}

編寫(xiě)createMatcher方法

import createRouteMap from './create-route-map'
export default function createMatcher(routes) {
    // 收集所有的路由路徑, 收集路徑的對(duì)應(yīng)渲染關(guān)系
    // pathList = ['/','/about','/about/a','/about/b']
    // pathMap = {'/':'/的記錄','/about':'/about記錄'...}
    let {pathList,pathMap} = createRouteMap(routes);
    
    // 這個(gè)方法就是動(dòng)態(tài)加載路由的方法
    function addRoutes(routes){
        // 將新增的路由追加到pathList和pathMap中
        createRouteMap(routes,pathList,pathMap);
    }   
    function match(){} // 稍后根據(jù)路徑找到對(duì)應(yīng)的記錄
    return {
        addRoutes,
        match
    }
}

創(chuàng)建映射關(guān)系,還需要createRouteMap方法

export default function createRouteMap(routes,oldPathList,oldPathMap){
    // 當(dāng)?shù)谝淮渭虞d的時(shí)候沒(méi)有 pathList 和 pathMap
    let pathList = oldPathList || []; 
    let pathMap = oldPathMap || Object.create(null);
    routes.forEach(route=>{
        // 添加到路由記錄,用戶配置可能是無(wú)限層級(jí),稍后要遞歸調(diào)用此方法
        addRouteRecord(route,pathList,pathMap);
    });
    return { // 導(dǎo)出映射關(guān)系
        pathList,
        pathMap
    }
}   
// 將當(dāng)前路由存儲(chǔ)到pathList和pathMap中
function addRouteRecord(route,pathList,pathMap,parent){
    // 如果是子路由記錄 需要增加前綴 
    let path = parent?`${parent.path}/${route.path}`:route.path;
    let record = { // 提取需要的信息
        path,
        component:route.component,
        parent
    }
    if(!pathMap[path]){
        pathList.push(path);
        pathMap[path] = record;
    }
    if(route.children){ // 遞歸添加子路由
        route.children.forEach(r=>{ 
            // 這里需要標(biāo)記父親是誰(shuí)
            addRouteRecord(r,pathList,pathMap,route);
        })
    }
}

vue路由有三種模式:hash / h5api /abstract,這里以hash為例

以hash路由為主,創(chuàng)建hash路由實(shí)例

import History from './base'
// hash路由
export default class HashHistory extends History{
    constructor(router){
        super(router);
    }
}
// 路由的基類
export default class History {
    constructor(router){
        this.router = router;
    }
}

如果是hash路由,打開(kāi)網(wǎng)站如果沒(méi)有hash默認(rèn)應(yīng)該添加#/

import History from './base';
function ensureSlash(){ 
    if(window.location.hash){
        return 
    }
    window.location.hash = '/'
}
export default class HashHistory extends History{
    constructor(router){
        super(router);
        ensureSlash(); // 確保有hash
    }
}

再把焦點(diǎn)轉(zhuǎn)向初始化邏輯

init(app){
        const history = this.history;
        // 初始化時(shí),應(yīng)該先拿到當(dāng)前路徑,進(jìn)行匹配邏輯

        // 讓路由系統(tǒng)過(guò)度到某個(gè)路徑
        const setupHashListener = ()=> {
            history.setupListener(); // 監(jiān)聽(tīng)路徑變化
        }
        history.transitionTo( // 父類提供方法負(fù)責(zé)跳轉(zhuǎn)
            history.getCurrentLocation(), // 子類獲取對(duì)應(yīng)的路徑
            // 跳轉(zhuǎn)成功后注冊(cè)路徑監(jiān)聽(tīng),為視圖更新做準(zhǔn)備
            setupHashListener
        )
}

這里我們要分別實(shí)現(xiàn) transitionTo(基類方法)、 getCurrentLocation 、setupListener

//getCurrentLocation
function getHash(){
    return window.location.hash.slice(1);
}
export default class HashHistory extends History{
    // ...
    getCurrentLocation(){
        return getHash();
    }
}
//setupListener
export default class HashHistory extends History{
    // ...
    setupListener(){
        window.addEventListener('hashchange', ()=> {
            // 根據(jù)當(dāng)前hash值 過(guò)度到對(duì)應(yīng)路徑
            this.transitionTo(getHash());
        })
    }
}
//核心方法TransitionTo
export function createRoute(record, location) { // {path:'/',matched:[record,record]}
    let res = [];
    if (record) { // 如果有記錄 
        while(record){
            res.unshift(record); // 就將當(dāng)前記錄的父親放到前面
            record = record.parent
        }
    }
    return {
        ...location,
        matched: res
    }
}
export default class History {
    constructor(router) {
        this.router = router;
        // 根據(jù)記錄和路徑返回對(duì)象,稍后會(huì)用于router-view的匹配
        this.current = createRoute(null, {
            path: '/'
        })
    }
    // 核心邏輯
    transitionTo(location, onComplete) {
        // 去匹配路徑
        let route = this.router.match(location);
        // 相同路徑不必過(guò)渡
        if(
            location === route.path && 
            route.matched.length === this.current.matched.length){
            return 
        }
        this.updateRoute(route); // 更新路由即可
        onComplete && onComplete();
    }
    updateRoute(route){ // 跟新current屬性
        this.current =route;
    }
}

不難發(fā)現(xiàn)路徑變化時(shí)都會(huì)更改current屬性,我們可以把current屬性變成響應(yīng)式的,每次current變化刷新視圖即可

export let _Vue;
export default function install(Vue) {
    _Vue = Vue;
    Vue.mixin({ // 給所有組件的生命周期都增加beforeCreate方法
        beforeCreate() {
            if (this.$options.router) { // 如果有router屬性說(shuō)明是根實(shí)例
                // ...
                Vue.util.defineReactive(this,'_route',this._router.history.current);
            } 
            // ...
        }
    });
    // 僅僅是為了更加方便
    Object.defineProperty(Vue.prototype,'$route',{ // 每個(gè)實(shí)例都可以獲取到$route屬性
        get(){
            return this._routerRoot._route;
        }
    });
    Object.defineProperty(Vue.prototype,'$router',{ // 每個(gè)實(shí)例都可以獲取router實(shí)例
        get(){
            return this._routerRoot._router;
        }
    })
}

其中不難看出 Vue.util.defineReactive 這個(gè)方法是vue中響應(yīng)式數(shù)據(jù)變化的核心。

export default class History {
    constructor(router) {
        // ...
        this.cb = null;
    }
    listen(cb){
        this.cb = cb; // 注冊(cè)函數(shù)
    }
    updateRoute(route){
        this.current =route;
        this.cb && this.cb(route); // 更新current后 更新_route屬性
    }
}

實(shí)現(xiàn)router-view

export default {
    functional:true,
    render(h,{parent,data}){
        let route = parent.$route;
        let depth = 0;
        data.routerView = true;
        while(parent){ // 根據(jù)matched 渲染對(duì)應(yīng)的router-view
            if (parent.$vnode && parent.$vnode.data.routerView){
                depth++;
            }
            parent = parent.$parent;
        }
        let record = route.matched[depth];
        if(!record){
            return h();
        }
        return h(record.component, data);
    }
}

實(shí)現(xiàn)router-link

export default {
    props:{
        to:{
            type:String,
            required:true
        },
        tag:{
            type:String
        }
    },
    render(h){
        let tag = this.tag || 'a';
        let handler = ()=>{
            this.$router.push(this.to);
        }
        return <tag onClick={handler}>{this.$slots.default}</tag>
    }
}

實(shí)現(xiàn)beforeEach

this.beforeHooks = [];
beforeEach(fn){ // 將fn注冊(cè)到隊(duì)列中
    this.beforeHooks.push(fn);
}
function runQueue(queue, iterator,cb) { // 迭代queue
    function step(index){
        if(index >= queue.length){
            cb();
        }else{
            let hook = queue[index];
            iterator(hook,()=>{ // 將本次迭代到的hook 傳遞給iterator函數(shù)中,將下次的權(quán)限也一并傳入
                step(index+1)
            })
        }
    }
    step(0)
}
export default class History {
    transitionTo(location, onComplete) {
        // 跳轉(zhuǎn)到這個(gè)路徑
        let route = this.router.match(location);
        if (location === this.current.path && route.matched.length === this.current.matched.length) {
            return
        }
        let queue = [].concat(this.router.beforeHooks);
        const iterator = (hook, next) => {
            hook(route,this.current,()=>{ // 分別對(duì)應(yīng)用戶 from,to,next參數(shù)
                next();
            });
        }
        runQueue(queue, iterator, () => { // 依次執(zhí)行隊(duì)列 ,執(zhí)行完畢后更新路由
            this.updateRoute(route);
            onComplete && onComplete();
        });
    }
    updateRoute(route) {
        this.current = route;
        this.cb && this.cb(route);
    }
    listen(cb) {
        this.cb = cb;
    }
}

7.vue原理(手寫(xiě)代碼,實(shí)現(xiàn)數(shù)據(jù)劫持)

1.核心點(diǎn):Object.defineProperty
2.默認(rèn)Vue在初始化數(shù)據(jù)時(shí),會(huì)給data中的屬性使用Object.defineProperty重新定義所有屬性,當(dāng)頁(yè)面取到對(duì)應(yīng)屬性時(shí)。會(huì)進(jìn)行依賴收集(收集當(dāng)前組件的watcher) 如果屬性發(fā)生變化會(huì)通知相關(guān)依賴進(jìn)行更新操作
3.本文主要描述的是vue2.0版本的實(shí)現(xiàn)

Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend() // ** 收集依賴 ** /
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      val = newVal
      childOb = !shallow && observe(newVal)
      dep.notify() /**通知相關(guān)依賴進(jìn)行更新**/
    }
})

數(shù)組方法的劫持涉及到原型相關(guān)的知識(shí),首先數(shù)組實(shí)例大部分方法都是來(lái)源于 Array.prototype對(duì)象。

但是這里不能直接篡改 Array.prototype 對(duì)象,這樣會(huì)影響所有的數(shù)組實(shí)例,為了避免這種情況,需要采用原型繼承得到一個(gè)新的原型對(duì)象:

const methods = [
  'push',
  'pop',
  'shift',
  'unshift',
  'sort',
  'reverse',
  'splice'
]
const arrayProto = Array.prototype
const injackingPrototype = Object.create(arrayProto);
methods.forEach(method => {
  const originArrayMethod = arrayProto[method]
  injackingPrototype[method] = function (...args) {
    const result = originArrayMethod.apply(this, args)
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) {
      // 對(duì)于新增的元素,繼續(xù)劫持
      // ob.observeArray(inserted)
    }
    // 通知變化
    return result
  }
})

通過(guò)對(duì)能改變?cè)瓟?shù)組的方法進(jìn)行攔截,達(dá)到對(duì)數(shù)組對(duì)象的劫持,遍歷直到普通值。

8.算法:樹(shù)的遍歷有幾種方式,實(shí)現(xiàn)下層次遍歷

前序遍歷

//根節(jié)點(diǎn)、左子樹(shù)、右子樹(shù)
function DLR(tree){
    console.log(tree.value);
    if(tree.left){
        DLR(tree.left);
    }
    if(tree.right){
        DLR(tree.right);
    }
}

中序遍歷

//左子樹(shù)、根節(jié)點(diǎn)、右子樹(shù)
function LDR(tree){
    if(tree.left){
        LDR(tree.left);
    }
    console.log(tree.value);
    if(tree.right){
        LDR(tree.right);
    }
}

后序遍歷

//左子樹(shù)、右子樹(shù)、根節(jié)點(diǎn)
function LRD(tree){
    if(tree.left){
        LRD(tree.left);
    }
    if(tree.right){
        LRD(tree.right);
    }
    console.log(tree.value);
}

三種遍歷操作大致相同,而差異就在于執(zhí)行額外操作的時(shí)機(jī),例如console.log

9.算法:判斷對(duì)稱二叉樹(shù)

首先判斷根節(jié)點(diǎn)是否相同
左子樹(shù)的右節(jié)點(diǎn)和右子樹(shù)的左節(jié)點(diǎn)是否相同
右子樹(shù)的左節(jié)點(diǎn)和左子樹(shù)的右節(jié)點(diǎn)是否相同

//一個(gè)對(duì)稱二叉樹(shù)
const symmetricalBinaryTree = {
  val: 8,
  left: {
    val: 6,
    left: { val: 2, left: null, right: null },
    right: { val: 4, left: null, right: null }
  },
  right: {
    val: 6,
    left: { val: 4, left: null, right: null },
    right: { val: 2, left: null, right: null }
  }
}
//一個(gè)非對(duì)稱二叉樹(shù)
const AsymmetricBinaryTree = {
  val: 8,
  left: {
    val: 6,
    left: { val: 2, left: null, right: null },
    right: { val: 4, left: null, right: null }
  },
  right: {
    val: 9,
    left: { val: 4, left: null, right: null },
    right: { val: 2, left: null, right: null }
  }
}

利用遞歸實(shí)現(xiàn)對(duì)稱二叉樹(shù)判斷

function isSymmetrical(root) {
  return isSymmetricalTree(root, root);
}

function isSymmetricalTree(node1, node2) {
  //判斷兩個(gè)節(jié)點(diǎn)都是否為空
  if (!node1 && !node2) {
    return true;
  }
  //判斷兩個(gè)節(jié)點(diǎn)是否存在一個(gè)為空
  if (!node1 || !node2) {
    return false;
  }
  //判斷兩個(gè)節(jié)點(diǎn)是否相同
  if (node1.val != node2.val) {
    return false;
  }
  return isSymmetricalTree(node1.left, node2.right) && isSymmetricalTree(node1.right, node2.left);
}

console.log(isSymmetrical(symmetricalBinaryTree));        //true
console.log(isSymmetrical(AsymmetricBinaryTree));        //false

主要是利用遞歸來(lái)判斷同一層級(jí)的節(jié)點(diǎn)左右是否同時(shí)相等,達(dá)到對(duì)稱判斷的目的。

 到此這篇關(guān)于2020字節(jié)跳動(dòng)前端面試題一面解析(附答案)的文章就介紹到這了,更多相關(guān)字節(jié)跳動(dòng)前端面試題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!

相關(guān)文章

  • 2020前端暑期實(shí)習(xí)大廠面經(jīng)

    這篇文章主要介紹了2020前端暑期實(shí)習(xí)大廠面經(jīng),主要包含了7個(gè)公司面經(jīng),華為,歡聚,京東,酷狗,美的,騰訊,網(wǎng)易,感興趣的可以了解一下
    2020-06-11
  • 前端js 基礎(chǔ)面試題目(提前看)

    在面試前必看的一些基礎(chǔ)面試題目,本文是小編給大家精心收藏整理的非常不錯(cuò),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下
    2020-04-22
  • 每個(gè)前端工程師都應(yīng)該去了解的前端面試題小結(jié)(推薦)

    面試對(duì)于我們每個(gè)程序員來(lái)說(shuō)都是非常重要的環(huán)節(jié),掌握一些面試題技巧是非常有必要的,今天小編給大家分享幾個(gè)js有關(guān)的面試題,需要的朋友參考下吧
    2020-04-15
  • 2020前端面試題之HTML篇(推薦)

    一場(chǎng)疫情過(guò)后,又要經(jīng)歷一次次面試,今天小編給大家分享2020前端面試題之HTML篇,非常不錯(cuò),對(duì)大家有所幫助,需要的朋友參考下吧
    2020-03-25
  • 2019大廠前端面試題小結(jié)

    這篇文章主要介紹了2019大廠前端面試題小結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2020-03-05
  • css的面試題目(前端常見(jiàn)面試題)

    隨著疫情的不斷好轉(zhuǎn),各地都開(kāi)始逐步的復(fù)工,當(dāng)然對(duì)我們來(lái)說(shuō),也馬上迎來(lái)所謂的金三銀四跳槽季。今天小編給大家分享前端常見(jiàn)面試題,需要的朋友跟隨小編一起看看吧
    2020-02-27
  • Web前端面試筆試題總結(jié)

    這篇文章主要介紹了Web前端面試筆試題總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-18
  • 80道前端面試經(jīng)典選擇題匯總

    這篇文章主要介紹了80道前端面試經(jīng)典選擇題匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)
    2020-01-08
  • 面試官常問(wèn)的web前端問(wèn)題大全

    這篇文章主要介紹了面試官常問(wèn)的web前端問(wèn)題大全,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-03
  • 前端十幾道含答案的大廠面試題總結(jié)

    這篇文章主要介紹了前端十幾道含答案的大廠面試題總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2020-01-02

最新評(píng)論