赞
踩
技术的浪潮奔腾不息,浪潮退去之后,留给我们自己的是方法论?还是过时的技术?
----
我们程序员,总喜欢谈论所谓“35岁魔咒”,好像“35岁魔咒”成了程序员的专利。然而事实上,35岁,是各行各业的职场人都会面临的问题。
究其根本,35岁是人到中年的转折点,如果我们在工作中的价值产出,更多依靠体力,那么就势必面临职业发展开始走下坡路的困境。
编程,原本是一种极富创造力,重视抽象思维与逻辑推演的工作,但我们相当一部分人,把编程做的像事务性工作,平淡如水,如果这样,“35岁魔咒”就会困扰我们。
在一个社会群体中,不同的人有不同的选择,我无意也无法改变大的环境,但希望帮助有意愿与“35岁魔咒”斗争的程序员,找到一点方向,多干几年!
从一道面试题说起
杨辉三角是我在面试中经常会问的一个问题,”请编程,按照指定格式输出前N行的杨辉三角"。
大部分候选人,拿到问题之后,就开始编码,首先写一个两层的循环,然后开始思考循环的终止条件,经过一番思考,给出一个自己都不相信的答案。我印象比较深刻的一次,候选人来自微信支付,也仅给出了获取前N行数据的方法,仍然未能找到按照指定格式打印的方法。
很多人会说,离开学校好几年了,算法早都忘记了,这种问题应该去问校招的同学。我不以为然,我在意的不是一个具体的算法,而是分析和解决问题的思路。我们可以忘记一些具体的算法,但忘记的同时,应该把算法中蕴含的解决问题的思路内化成自己的武器。
接下来,我和大家介绍下我如何看待这个问题。
图灵奖得主N.Wirth提出"程序 = 算法 + 数据结构",我更习惯说“程序 = 数据 + 过程”。
数据视角
首先,我们站在数据的视角,来审视这道面试题,可以发现:
1、可以使用二维数组(以php语言为例)描述杨辉三角的前N行数据
- [
- [1],
- [1, 1],
- [1, 2, 1],
- [1, 3, 3, 1],
- ]
2、行的数据之间,存在如下规则:
1)每行两边数字恒为1
2)每行中间的数字,是上一行交叉位置两个数字的和
因此,可以用一个伪代码描述这种关系:
- F(1) = [1]
- F(N) = [
- 1,
- F(N-1)[0] + F(N-1)[1],
- F(N-1)[1] + F(N-1)[2],
- ...,
- F(N-1)[N-2] + F(N-1)[N - 1],
- 1
- ]
过程视角
接下来,我们站在过程视角,审视这道面试题。首先,它的过程可以分为两个步骤:1)获取前N行杨辉三角的数据;2)按照图示对齐的方式进行打印。
第一步,基于我们前面对数据的分析,可以轻易的得出对应的方法设计:
- function yanghui_datas($n); // 获取前N行杨辉三角数据
- function yanghui_line_datas($prev_line_data); // 依据前一行数据获取下一行数据
第二步,依据图示对齐方式进行打印。单纯的打印是很简单的,所以,关键在于“对齐”。
解决对齐的方法,无非就是给相应的位置留白。但我们发现,该怎么留白是不清晰的。那就进一步思考,导致留白逻辑不清晰的难点问题是什么?
通过分析,可以看到,如果只需要输出前5行,那么每个数字都是个位数,如果要输出第6行,那么就开始有十位数。因此,是数字宽度的不确定性,产生了这里的困难。
逆向思维,如果数字的宽度确定,那就没有这个困难。所以:
我们把每个数字放到一个等宽的格子中。这样,整个问题就清晰了:
- 格子宽度 = 最大数字宽度 + 1
- 行前留白 = (LINE_COUNT - LINE_NO) * 格子宽度 / 2
-
- 格子内部: (数字居中)
- 左留白 = (格子宽度 - 数字宽度) / 2
- 右留白 = 格子宽度 - 左留白 - 数字宽度
编码
经过上面的分析,代码几乎就跃然纸上了。
- // 获取前N行杨辉三角数据
- function yanghui_datas($n_line) {
- $datas = [];
- $prev_line_datas = [];
- while ($n_line -- > 0) {
- $line_datas = yanghui_line_datas($prev_line_datas);
- array_push($datas, $line_datas);
- $prev_line_datas = $line_datas;
- }
- return $datas;
- }
-
- // 通过前一行数据获取下一行数据
- function yanghui_line_datas($prev_line_datas) {
- if (empty($prev_line_datas)) {
- return [1];
- }
-
- $line_datas = [];
-
- array_push($line_datas, 1); // 行首
- for ($i = 1; $i < count($prev_line_datas); $i ++) {
- array_push($line_datas, $prev_line_datas[$i - 1] + $prev_line_datas[$i]);
- }
-
- array_push($line_datas, 1); // 行尾
-
- return $line_datas;
- }
-
- // 打印指定的杨辉三角数据
- function yanghui_print($datas) {
- $space = ' '; // 留白字符
- $newline = '<br />'; // 换行符
-
- $max_num = yanghui_max_num($datas); // 最大数字
- $max_num_width = yanghui_num_width($max_num); // 最大宽度
- $unit_width = $max_num_width + 1; // 格子宽度
- $line_count = count($datas); // 行数
-
- foreach ($datas as $idx => $line_datas) {
- $line_no = $idx + 1; // 行号
- $line_prefix_width = ($line_count - $line_no) * $unit_width / 2; // 行前留白数
-
- echo str_repeat($space, $line_prefix_width);
- foreach ($line_datas as $num) {
- $num_width = yanghui_num_width($num); // 数字宽度
- $left_width = intval(($unit_width - $num_width) / 2); // 格子内左留白宽度
- $right_width = $unit_width - $left_width - $num_width; // 格子内右留白宽度
-
- echo str_repeat($space, $left_width);
- echo $num;
- echo str_repeat($space, $right_width);
- }
- echo $newline;
- }
- }
-
- // 获取最大数
- function yanghui_max_num($datas) {
- $max = 0;
- foreach ($datas as $line_datas) {
- foreach ($line_datas as $num) {
- $max = max($max, $num);
- }
- }
- return $max;
- }
-
- // 获取数字的宽度
- function yanghui_num_width($num) {
- return strlen(strval($num));
- }
最后,过程的两部分组装起来,就是想要的结果。
- function yanghui_dump($n) {
- $datas = yanghui_datas($n);
- yanghui_print($datas);
- }
补充
有人说,杨辉三角中的数字,可以依据坐标直接计算得到,没关系,替换掉获取数据的对应部分即可。
启示
当我们面对问题时,有两种思维模式:经验型和能力型。
经验型思维,搜索自己的知识库,发现杨辉三角应该要一个两层循环,就开始执行;执行了一步之后,发现卡住了,下一个问题自己的知识库中没有,然后就陷入了沉思!
能力型思维,先分析问题的本质构成,对问题进行分解,将复杂的大问题转换成多个简单的小问题,抽丝剥茧,在自己的知识库中搜索每个小问题的答案,最终解决问题。
两种思维模式的优劣势显而易见,经验型思维适合解决确定的、已知的、简单的问题,效率更高;能力型思维适合解决不确定的、未知的、复杂的问题,适应性更广。
通过程序设计锻炼能力型思维
编程,是一项极富创造力,注重逻辑和推演的工作。
当我们开始编程之前,首先需要站在具体问题的层面,对目标系统进行分析,然后,又需要站在抽象视角层面,把目标系统拔高一层进行演绎。在具体与抽象之间,不断的推敲,找到合理的对现实的抽象描述。
这个分析推演的过程,就是寻找事物本质的过程。只不过,我们的日常工作,面对大量繁杂的需求,没有过多的时间进行设计层面的思考。现实,把我们磨成了需求翻译机器。
大部分程序员其实不甘于此,所以,我想通过一份教程,帮助有意愿寻求改变的同学,促进这种改变的达成。
2014年,我编写了目前公司使用的框架,已经稳定运行超过5年,支撑了超过60万行业务代码,但它自身只有6000行代码。接下来一段时间,我会以它为蓝本,站在重新编写一个框架的角度上,全面的复现编写框架的思考、分析、设计、实现整个过程,并将其整理为一份视频教程,以期能帮助大家寻找到程序设计的感觉。(自愿付费,可自由分享与传播)
整个教程大致分12讲,每讲有一个独立的主题,每讲时间1-3小时不等,并配以一篇公众号文章发布。大的层面框架分为3个部分:与外部环境的交互、对业务层的封装约束、ORM之类的辅助工具。
教程
因文字表现力有限,本文仅作为一个引子,具体关于职业发展的分析、教程想要传递的价值、以及传递价值采用的方法,请下载视频教程深入学习。
【十年一剑,透过框架理解抽象思维】是我录制的一套系列教程,通过重现开发一套框架的思考、分析、设计、实现全过程,帮助大家寻找程序设计的灵感(自愿付费,可自由传播分享)。教程会通过公众号《抽象思维》发布。
今天发布的是第一讲《录制教程的意义》,感兴趣想要深入学习的同学,请扫码下载视频教程(下载地址: https://pan.baidu.com/wap/init?surl=IZ24Az5GFpQoQSD4WbfR8g 提取密码:rcga)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。