当前位置: 首页 > 面试经验 >

8.20 网易互联网前端笔试

优质
小牛编辑
97浏览
2023-03-28

8.20 网易互联网前端笔试

前言:

  1. 已经过去好几天了,本来没想着写笔试贴的,一来过去蛮久了,可能没啥价值了;二来还有问题没有解决,对大家没啥帮助,也不好意思发出来。但是今天京东笔试竟然遇到相似的题目了,觉得这些过去的笔试还是有点价值的;再者哪怕仅仅把自己的思路发出来,有感兴趣的伙伴集思广益,说不定就能解决了。
  2. 一共4道编程题,没有选择题。笔试了这么多家,就网易的前端和其他的考一样的题目。我感觉这四道题目很像。说不出来哪里像
  3. 做题前理清思路很重要,比如“长城数”那题,我先是想的“长城两块砖,而且数据只能增加,那最终结果就是取原数组中第一大和第二大的数字”,但是这样想是不对的,比如“30、100、5、70”虽然前两个大的数是100、70,但是最终结果是“30、100、30、100”。正确的思路是分别取奇、偶数项的最大值!
  4. 笔试中,首先要尝试发现规律,简化操作;但若发现不了,也要先尝试暴力解法,暴力的代码量往往比较少;暴力解法不能AC,且有时间,就用正常的解法如“dp、回溯……”。【时间很重要!

编程:

  1. 感谢大佬把题目贴出来,题目链接:链接1 链接2

1. 删除数位求是否能整除

思路:
  1. 遍历:假设a有n位,b有m位,如果用遍历的话,最多有种可能(Cn1 + …… + Cn(n-1))*(Cm1 + …… + Cm(m-1))种可能性
  2. 从“贪心”的角度来说,应该从删除位数少向删除位数多遍历
  3. 从题意来看,a、b至少得留一位,不能全删除了
/* 
  参数a、b是数组的形式,因为数组才好操作删除位数。不知道纯数字怎么删除某一位的
*/

console.log(getRes([1, 2, 3, 4], [9, 9])); //  2
console.log(getRes([1, 2, 3, 4], [9, 9,9,9,9])); // 1
function getRes(a, b) {
  // 直接整除,不用操作
  if(isBase(a, b)) {
    return 0
  } else {
    let alen = a.length, blen = b.length, bmap = new Map(), result = Number.MAX_VALUE
    for(let i = 0; i <= alen - 1; ++i) {
      let res1 = removeNum(i, a);
      for(let j = 0; j <= blen - 1; ++j) {
        if(!bmap.has(j)) {
          let res = removeNum(j, b);
          bmap.set(j, res)
        }
        let res2 = bmap.get(j);
        if(gotyou(res1, res2)) {
          result = Math.min(result, i + j);
        }
      }
    }
    return result === Number.MAX_VALUE ? -1 : result;
  }
}

function isBase(a, b) {
  let num1 = parseInt(a.join(''))
  let num2 = parseInt(b.join(""));
  if (num1 === 0|| num2 === 0) return true;
  return num1 % num2 === 0 || num2 % num1 === 0;
}

/* 
  j是要删除的位数;b是数组
  返回删除j位数后数组的组合
*/
function removeNum(j, b) {
  let res = [], currentList = [];
  // 删除j位,等价于从b中取出b.length - j位。
  // 也就是从b.length位中取b.length - j位的组合,但是不能破坏原有的顺序,如1234只能取出123来,却不能取出321来————这里可以参考力扣46题全排列,用回溯!
  let targetCount = b.length - j, used = new Array(b.length).fill(false);
  backTrack(currentList, b, used, 0);
  return res

  function backTrack(currentList, nums, used, start) {
    if(currentList.length === targetCount) {
      // console.log(currentList);
      // 注意复杂数据类型的赋值,这里浅拷贝下!
      res.push(currentList.slice(0));
      return 
    }
    for(let i = start; i < nums.length; ++i) {
      if(used[i] === true) {
        continue
      } else if (nums.length - i + 1 < targetCount - currentList.length) {
        // 这种情况下,往后取肯定不够targetCount位,就直接返回吧,不要往下了
        return;
      } else {
        currentList.push(nums[i]);
        used[targetCount] === true;
        // 为了保证顺序,从i+1往后取
        backTrack(currentList, nums, used, i + 1);
        currentList.pop(nums[i]);
        used[targetCount] === true;
      }
    }
  }
}

// 删除了某一位后拿来这里比较下,看能不能整除
function gotyou(arr1, arr2) {
  for(let num1 of arr1) {
    for(let num2 of arr2) {
      if (isBase(num1, num2)) {
        return true;
      }
    }
  }
  return false
}



2. 长城数

思路:
  1. 分别找到奇、偶数项的最大值。如果最大值相同就短的加一,即如果一共是偶数个数,随便哪个加1,如果一共是奇数个数,那就偶数位加1——>所以都让偶数位加1就够了
  2. 今天京东笔试也考到了长城数,但是有点差别。
    console.log(getNum([1,1,4,5,1,4]));  // 11
    
    function getNum(arr) {
      let oddMax = 0, evenMax = 0, res = 0;
      for(let i = 0; i < arr.length; ++i) {
        if(i % 2 === 0) {
          oddMax = Math.max(oddMax, arr[i]);
        } else {
          evenMax = Math.max(evenMax, arr[i]);
        }
      }
      if(oddMax === evenMax) {
        evenMax += 1;
      }
    
      for (let i = 0; i < arr.length; ++i) {
        if (i % 2 === 0) {
          res += (oddMax - arr[i]);
        } else {
          res += (evenMax - arr[i]);
        }
      }
      return res;
    }


3. 百年好“e”

思路:
  1. 题干里说了两个限制条件,在'好e'`最多`的情况下,需要修改的`最少`位数。而当字符串位数已知的时候,'好e'的个数是可以预先求出来的,如3位、4位字符,最多一个'好e';5位字符,最多两个好e。
  2. 我想的是求出来'好e'的个数,就知道其组合了,然后和原来的字符串比较即可。但是我这里想错了,如'reddee'最多有两个'好e',最终应该是'rederd'或者'deredr',但是'redred'也是两个'好e'呀,情况还有很多种,所以此路不通
  3. 暂无思路,也没看到好的解法。

4. 三元组数

- 思路:当时时间紧迫,我就用了暴力解法,过了60%。思路是,遍历数组,当arr[i] === arr[j]时,看i, j中间有几个符合要求的数。
function getNum(arr) {
  let sum = 0
  for(let i = 0; i < arr.length - 1; ++i) {
    for(let j = i + 1; j < arr.length; ++j) {
      if(arr[j] === arr[i]) {
        sum += getPart(i, j);
      }
    }
  }

  return sum

  function getPart(i, j) {
    let res1 = 0
    for(let z = i + 1; z < j; ++z) {
      if(arr[z] < arr[i]) {
        res1++;
      }
    }
    return res1
  }
}

console.log(getNum([3, 1, 3, 4, 3, 4])); // 3


- 优化思路,上面确实存在重复计算的情况,如[3,1,2,3,1,3],算arr[0] 和arr[5]之间的三元组数时,可以用 arr[0] 和 arr[3] 加上 arr[3] 和arr[5]之间的三元组数,而前者是算过的,那就用个备忘录memo去记录一下,也就是用空间换时间啦,可以降低时间复杂度。
function getNum(arr) {
  let sum = 0, memo = [-1,-1,-1];
  for (let i = 0; i < arr.length - 1; ++i) {
    for (let j = i + 1; j < arr.length; ++j) {
      if (arr[j] === arr[i]) {
        sum += getPart(i, j);
      }
    }
  }

  return sum;

  function getPart(i, j) {
    console.log(i,j);
    let res1 = 0;
    if (memo[0] !== i) {
      // 这种情况下就是备忘录没用
      for (let z = i + 1; z < j; ++z) {
        if (arr[z] < arr[i]) {
          res1++;
        }
      }
    } else {
      // 备忘录起作用了
      for (let z = memo[1] + 1; z < j; ++z) {
        if (arr[z] < arr[i]) {
          res1++;
        }
      }
      res1 += memo[2]
    }
    // memo记录了起点和终点,以及这个中间符合要求的三元组数!
    memo = [i, j, res1];
    return res1;
  }
}

console.log(getNum([3, 1 ,3 ,4 ,3, 4])); // 3
- 但是这个memo还不够,还是有重复计算的情况,再优化吧!



#网易笔试##网易##前端#
 类似资料: