当前位置:   article > 正文

程序员,你还能干几年?_我们程序员,总喜欢谈论所谓“35岁魔咒”,好像“35岁魔咒”成了程序员的专利。然而

我们程序员,总喜欢谈论所谓“35岁魔咒”,好像“35岁魔咒”成了程序员的专利。然而

技术的浪潮奔腾不息,浪潮退去之后,留给我们自己的是方法论?还是过时的技术?

----

我们程序员,总喜欢谈论所谓“35岁魔咒”,好像“35岁魔咒”成了程序员的专利。然而事实上,35岁,是各行各业的职场人都会面临的问题。

究其根本,35岁是人到中年的转折点,如果我们在工作中的价值产出,更多依靠体力,那么就势必面临职业发展开始走下坡路的困境。

编程,原本是一种极富创造力,重视抽象思维与逻辑推演的工作,但我们相当一部分人,把编程做的像事务性工作,平淡如水,如果这样,“35岁魔咒”就会困扰我们。

在一个社会群体中,不同的人有不同的选择,我无意也无法改变大的环境,但希望帮助有意愿与“35岁魔咒”斗争的程序员,找到一点方向,多干几年!

从一道面试题说起

杨辉三角是我在面试中经常会问的一个问题,”请编程,按照指定格式输出前N行的杨辉三角"。

 

大部分候选人,拿到问题之后,就开始编码,首先写一个两层的循环,然后开始思考循环的终止条件,经过一番思考,给出一个自己都不相信的答案。我印象比较深刻的一次,候选人来自微信支付,也仅给出了获取前N行数据的方法,仍然未能找到按照指定格式打印的方法。

很多人会说,离开学校好几年了,算法早都忘记了,这种问题应该去问校招的同学。我不以为然,我在意的不是一个具体的算法,而是分析和解决问题的思路。我们可以忘记一些具体的算法,但忘记的同时,应该把算法中蕴含的解决问题的思路内化成自己的武器。

接下来,我和大家介绍下我如何看待这个问题。

图灵奖得主N.Wirth提出"程序 = 算法 + 数据结构",我更习惯说“程序 = 数据 + 过程”。

数据视角

首先,我们站在数据的视角,来审视这道面试题,可以发现:

1、可以使用二维数组(以php语言为例)描述杨辉三角的前N行数据

  1. [
  2.   [1],
  3.   [1, 1],
  4.   [1, 2, 1],
  5.   [1, 3, 3, 1],
  6. ]

2、行的数据之间,存在如下规则:

1)每行两边数字恒为1

2)每行中间的数字,是上一行交叉位置两个数字的和

因此,可以用一个伪代码描述这种关系:

  1. F(1) = [1]
  2. F(N) = [
  3.     1,
  4.     F(N-1)[0] + F(N-1)[1],
  5.     F(N-1)[1] + F(N-1)[2],
  6.     ...,
  7.     F(N-1)[N-2] + F(N-1)[N - 1],
  8.     1
  9. ]

过程视角

接下来,我们站在过程视角,审视这道面试题。首先,它的过程可以分为两个步骤:1)获取前N行杨辉三角的数据;2)按照图示对齐的方式进行打印。

第一步,基于我们前面对数据的分析,可以轻易的得出对应的方法设计:

  1. function yanghui_datas($n); // 获取前N行杨辉三角数据
  2. function yanghui_line_datas($prev_line_data); // 依据前一行数据获取下一行数据

第二步,依据图示对齐方式进行打印。单纯的打印是很简单的,所以,关键在于“对齐”。

解决对齐的方法,无非就是给相应的位置留白。但我们发现,该怎么留白是不清晰的。那就进一步思考,导致留白逻辑不清晰的难点问题是什么?

通过分析,可以看到,如果只需要输出前5行,那么每个数字都是个位数,如果要输出第6行,那么就开始有十位数。因此,是数字宽度的不确定性,产生了这里的困难。

逆向思维,如果数字的宽度确定,那就没有这个困难。所以:

 

我们把每个数字放到一个等宽的格子中。这样,整个问题就清晰了:

  1. 格子宽度 = 最大数字宽度 + 1
  2. 行前留白 = (LINE_COUNT - LINE_NO) * 格子宽度 / 2
  3. 格子内部: (数字居中)
  4. 左留白 = (格子宽度 - 数字宽度)  / 2
  5. 右留白 = 格子宽度 - 左留白 - 数字宽度

编码

经过上面的分析,代码几乎就跃然纸上了。

  1. // 获取前N行杨辉三角数据
  2. function yanghui_datas($n_line) {
  3.     $datas = []; 
  4.     $prev_line_datas = []; 
  5.     while ($n_line -- > 0) {
  6.         $line_datas = yanghui_line_datas($prev_line_datas);
  7.         array_push($datas, $line_datas);
  8.         $prev_line_datas = $line_datas;
  9.     }   
  10.     return $datas;
  11. }
  12. // 通过前一行数据获取下一行数据
  13. function yanghui_line_datas($prev_line_datas) {
  14.     if (empty($prev_line_datas)) {
  15.         return [1];
  16.     }   
  17.     $line_datas = []; 
  18.     array_push($line_datas, 1); // 行首
  19.     for ($i = 1; $i < count($prev_line_datas); $i ++) {
  20.         array_push($line_datas, $prev_line_datas[$i - 1] + $prev_line_datas[$i]);
  21.     }   
  22.     array_push($line_datas, 1); // 行尾
  23.     return $line_datas;
  24. }
  25. // 打印指定的杨辉三角数据
  26. function yanghui_print($datas) {
  27.     $space         = '&nbsp;'; // 留白字符
  28.     $newline       = '<br />'; // 换行符
  29.     $max_num       = yanghui_max_num($datas); // 最大数字
  30.     $max_num_width = yanghui_num_width($max_num); // 最大宽度
  31.     $unit_width    = $max_num_width + 1; // 格子宽度
  32.     $line_count    = count($datas); // 行数
  33.     foreach ($datas as $idx => $line_datas) {
  34.         $line_no           = $idx + 1; // 行号
  35.         $line_prefix_width = ($line_count - $line_no) * $unit_width / 2; // 行前留白数
  36.         echo str_repeat($space, $line_prefix_width);
  37.         foreach ($line_datas as $num) {
  38.             $num_width   = yanghui_num_width($num); // 数字宽度
  39.             $left_width  = intval(($unit_width - $num_width) / 2); // 格子内左留白宽度
  40.             $right_width = $unit_width - $left_width - $num_width; // 格子内右留白宽度
  41.             echo str_repeat($space, $left_width);
  42.             echo $num;
  43.             echo str_repeat($space, $right_width);
  44.         }
  45.         echo $newline;
  46.     }
  47. }
  48. // 获取最大数
  49. function yanghui_max_num($datas) {
  50.     $max = 0;
  51.     foreach ($datas as $line_datas) {
  52.         foreach ($line_datas as $num) {
  53.             $max = max($max, $num);
  54.         }   
  55.     }   
  56.     return $max;
  57. }
  58. // 获取数字的宽度
  59. function yanghui_num_width($num) {
  60.     return strlen(strval($num));
  61. }

最后,过程的两部分组装起来,就是想要的结果。

  1. function yanghui_dump($n) {
  2.     $datas = yanghui_datas($n);
  3.     yanghui_print($datas);
  4. }

补充

有人说,杨辉三角中的数字,可以依据坐标直接计算得到,没关系,替换掉获取数据的对应部分即可。

启示

当我们面对问题时,有两种思维模式:经验型和能力型。

经验型思维,搜索自己的知识库,发现杨辉三角应该要一个两层循环,就开始执行;执行了一步之后,发现卡住了,下一个问题自己的知识库中没有,然后就陷入了沉思!

能力型思维,先分析问题的本质构成,对问题进行分解,将复杂的大问题转换成多个简单的小问题,抽丝剥茧,在自己的知识库中搜索每个小问题的答案,最终解决问题。

两种思维模式的优劣势显而易见,经验型思维适合解决确定的、已知的、简单的问题,效率更高;能力型思维适合解决不确定的、未知的、复杂的问题,适应性更广。

通过程序设计锻炼能力型思维

编程,是一项极富创造力,注重逻辑和推演的工作。

当我们开始编程之前,首先需要站在具体问题的层面,对目标系统进行分析,然后,又需要站在抽象视角层面,把目标系统拔高一层进行演绎。在具体与抽象之间,不断的推敲,找到合理的对现实的抽象描述。

这个分析推演的过程,就是寻找事物本质的过程。只不过,我们的日常工作,面对大量繁杂的需求,没有过多的时间进行设计层面的思考。现实,把我们磨成了需求翻译机器。

大部分程序员其实不甘于此,所以,我想通过一份教程,帮助有意愿寻求改变的同学,促进这种改变的达成。

2014年,我编写了目前公司使用的框架,已经稳定运行超过5年,支撑了超过60万行业务代码,但它自身只有6000行代码。接下来一段时间,我会以它为蓝本,站在重新编写一个框架的角度上,全面的复现编写框架的思考、分析、设计、实现整个过程,并将其整理为一份视频教程,以期能帮助大家寻找到程序设计的感觉。(自愿付费,可自由分享与传播)

整个教程大致分12讲,每讲有一个独立的主题,每讲时间1-3小时不等,并配以一篇公众号文章发布。大的层面框架分为3个部分:与外部环境的交互、对业务层的封装约束、ORM之类的辅助工具。

教程

因文字表现力有限,本文仅作为一个引子,具体关于职业发展的分析、教程想要传递的价值、以及传递价值采用的方法,请下载视频教程深入学习。

【十年一剑,透过框架理解抽象思维】是我录制的一套系列教程,通过重现开发一套框架的思考、分析、设计、实现全过程,帮助大家寻找程序设计的灵感(自愿付费,可自由传播分享)。教程会通过公众号《抽象思维》发布。

今天发布的是第一讲《录制教程的意义》,感兴趣想要深入学习的同学,请扫码下载视频教程(下载地址: https://pan.baidu.com/wap/init?surl=IZ24Az5GFpQoQSD4WbfR8g 提取密码:rcga)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/883950
推荐阅读
相关标签
  

闽ICP备14008679号