不开玩笑的,计算机专业有什么不写代码但又能干一辈子的工作?

文摘   2024-11-23 10:07   山西  

最近刷到一个帖子,一个学计算机的朋友问:“有什么不用写代码还能干一辈子的工作,别开玩笑兄弟们?”这问题问得挺扎心的,毕竟学计算机的,不写代码还真有点对不起这个专业。但网友们的回复也很有意思,咱一起来看看。

有人说:“大学老师,写一份教案用到退休。”这确实不用天天敲代码,最多敲敲讲义,日子倒也挺惬意的。

还有网友提到:“网吧网管,会修电脑就行,不用写代码,能干一辈子,就是工资不高。”干一辈子是可以的,但有多少人愿意呢?

当然,也有直接泼冷水的:“你先开的玩笑。”哈哈,兄弟这是真实之言,学计算机的,不写代码,总觉得差点意思。

也有网友认真建议:“考公考编。”虽然不用写代码,但这条路上竞争也不小。

所以说,学计算机如果不想写代码,选工作还是得看自己的兴趣和追求。你愿意平平稳稳,还是想跳出舒适圈?反正我觉得,选啥都别亏待了自己。

今日算法题


好了,要想在IT混的好,还得看你的技术怎么样,我们言归正传,今天咱们聊聊尾递归这个话题。要是面试官问你“举例说明尾递归的理解及其应用场景”,你会怎么回答?别急,咱们一起来解剖一下这个经典的面试问题。

尾递归是递归的一种特殊形式,说白了,就是在一个函数的最后一步调用自身,而且没有其他额外操作。这样做的好处是啥呢?

简单来说,它能优化内存使用,避免普通递归可能遇到的“栈溢出”问题。啥是栈溢出?想象一下,你的电脑递归调用太多了,系统撑不住,就崩了。这不就跟吃太多饭肚子爆炸一个道理么?

举个简单的例子,阶乘大家都熟悉吧?如果用普通递归来实现计算 ( n! ) (也就是从1乘到n),代码是这样的:

function factorial(n{
  if (n === 1return 1;
  return n * factorial(n - 1);
}

console.log(factorial(5)); // 120

这个函数运行时,调用栈就像一层层的积木,每次递归都得把“n * factorial(n - 1)”压进栈里。最后计算完成时再一层层拆积木,把结果拿出来。如果数字特别大,比如factorial(10000),你想象一下,积木能堆多高?

换成尾递归呢?代码这么写:

function factorial(n, total = 1{
  if (n === 1return total;
  return factorial(n - 1, n * total);
}

console.log(factorial(5)); // 120

这里妙就妙在“尾递归”的设计:每次调用直接把当前的结果传递给下一层,不用积木似的堆起来。就好比一个勤劳的小蜜蜂,每次只记住当前的进度,不用扛着整个任务走。结果就是啥?即使 factorial(10000) 也不会栈溢出。是不是听起来有点神奇?

那么尾递归的应用场景有哪些呢?其实很多地方都能用上。下面几个例子供大家参考:

1、数组求和

普通递归写法是这样的:

function sumArray(arr{
  if (arr.length === 1return arr[0];
  return arr.pop() + sumArray(arr);
}

console.log(sumArray([1234])); // 10

这个方法看似优雅,但当数组特别大时会崩溃,因为调用栈太深。换成尾递归就好多了:

function sumArray(arr, total = 0{
  if (arr.length === 0return total;
  return sumArray(arr.slice(1), total + arr[0]);
}

console.log(sumArray([1234])); // 10

尾递归版本每次调用都干净利落,把当前的累加值传给下一层,稳如老狗。

2、斐波那契数列

斐波那契数列那玩意儿,前两项是1,后面每一项等于前两项之和。普通递归实现是这样的:

function fibonacci(n{
  if (n <= 2return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(fibonacci(10)); // 55

这个写法性能堪忧,因为每次都要计算两次,效率感人。尾递归版本:

function fibonacci(n, a = 1, b = 1{
  if (n <= 2return b;
  return fibonacci(n - 1, b, a + b);
}

console.log(fibonacci(10)); // 55

看看尾递归的魅力,每次只传递当前两个数的值,计算速度嗖嗖的。

3、数组扁平化

要把一个嵌套数组变成一维数组,普通写法用递归:

function flatten(arr{
  let result = [];
  arr.forEach(item => {
    if (Array.isArray(item)) {
      result = result.concat(flatten(item));
    } else {
      result.push(item);
    }
  });
  return result;
}

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

尾递归优化版:

function flatten(arr, result = []{
  arr.forEach(item => {
    if (Array.isArray(item)) {
      flatten(item, result);
    } else {
      result.push(item);
    }
  });
  return result;
}

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

尾递归版本只用一个数组保存结果,不用反复创建中间结果数组,内存占用更省。

4、对象格式化

有时我们想把对象的所有键变成小写,比如:

let obj = {
  A'1',
  B: {
    C'2',
    D: {
      E'3'
    }
  }
};

转换后变成:

let obj = {
  a'1',
  b: {
    c'2',
    d: {
      e'3'
    }
  }
};

尾递归实现:

function keysToLowerCase(obj{
  let result = {};
  for (let key in obj) {
    let newKey = key.toLowerCase();
    if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
      result[newKey] = keysToLowerCase(obj[key]);
    } else {
      result[newKey] = obj[key];
    }
  }
  return result;
}

console.log(keysToLowerCase(obj));

尾递归方式逐层遍历,既简洁又高效。

最后给大家总结一下如何回答面试题:

  • 定义清楚:尾递归是递归的一种特殊形式,特点是递归调用发生在函数的最后一步。
  • 优缺点简述:尾递归通过优化栈使用,避免栈溢出;但只有在支持尾调用优化的环境下(如部分JS引擎)才能完全发挥作用。
  • 举例说明:阶乘、斐波那契数列、数组求和、扁平化操作和对象格式化等。
  • 强调实践:说明尾递归的实际意义在于优化性能和内存,尤其在处理大规模数据或深度嵌套时。

目前,对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。

虎哥私藏精品 热门推荐

虎哥作为一名老码农,整理了全网最前端资料合集

资料包含了《前端面试题PDF合集》、《前端学习视频》、《前端项目及源码》,总量高达108GB。

全部免费领取全面满足各个阶段程序员的学习需求!

web前端专栏
回复 javascript,获取前端面试题。分享前端教程,AI编程,AI工具,Tailwind CSS,Tailwind组件,javascript教程,webstorm教程,html教程,css教程,nodejs教程,vue教程。
 最新文章