Becomin' Charles

算法 | LNMP | Flutter | Mac

Becomin' Charles

这个原题目可以去 LC 看。我看到这个题目的想法就是硬做,无非是数相同的数字有几个的问题,然后用两个数字描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def countAndSay(self, n: int) -> str:
if n == 1:
return "1"
say, i, new = "1", 1, ""
while i < n:
num = say[0]
count = 0
for j in range(len(say)):
if num == say[j]:
count += 1
else:
new += str(count) + num
count = 1
num = say[j]
new += str(count) + num
say, new = new, ""
i += 1
return say

这是我写的代码,就是迭代的去逐个计算。

我看了一下题解,有提到查表法的,这个当然是正确的解法,这个题目,有非常小的问题空间 1 <= n <= 30 一共才30个,当然,生成 30 个答案,还是要靠算法去计算,用查表法,只是增加了喜剧效果和真的很省时间,可以 Beats 100%。

另外,值得一提的是,有不少人提到了递归法,这个题目显然具备了递归的结构,比如,计算第 n 个串,本质上就是对第 n - 1 个串的描述。所以,可以用递归法,不过这个题目的特殊之处在于,用递归写,也并没有简单多少,反倒增加了栈的成本。没什么意思,其实栈里只是存储了 n - 1 个串的表达而已,用一个变量就可以存了。像我上面写的代码一样。

这个题目就像标题一样直接,第一步,找到最后一个单词,第二步,计算长度。

我就写了这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
def lengthOfLastWord(self, s: str) -> int:
idx = len(s) - 1
flag = False
count = 0
while idx >= 0:
if s[idx] == " ":
if not flag:
idx -= 1
continue
else:
break

flag = True
count += 1
idx -= 1
return count

写完看了题解,发现我写得还是比较啰嗦的,多用了很多的变量。题解里有一些解法,上来先处理尾空格,然后再开一个循环开始计数,原理是一样的,但是写起来简洁了很多,我个人觉得很好。

另外有人提到,为啥不用 trim,是呀,题目也没说不可以用 trim,如果对类库很熟的话,完全可以用 trim,不能因为是算法题,就陷入思维定势吧…… 也是蠢得可爱……

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def lengthOfLastWord(self, s: str) -> int:
s = s.strip()
idx, count = len(s) - 1, 0
while idx >= 0:
if s[idx] != " ":
count += 1
else:
return count
idx -= 1
return 0

用 Python 的 strip() 函数,精简了一下,去掉尾空格后,数数,遇到空格停止。

这个问题也是极其的简洁,就是把一个整数,按位拆分到一个 list 里面,然后,在低位加一,然后让你处理好进位问题。学了几次的列表反转,终于可以在这里派上用场了,难得我想起来用一次:

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def plusOne(self, digits: List[int]) -> List[int]:
digits, carry = digits[::-1], 1
for i in range(len(digits)):
digits[i] += carry
carry, digits[i] = digits[i] // 10, digits[i] % 10
if carry == 0:
break
if carry == 1:
digits.append(1)
return digits[::-1]

数字的加法,是把 1 加到列表的最右边,但是列表的迭代从最左边比较容易,所以我反转一下,当然这有代价。

然后,我假设现在进位已经有 1 了,原题目正好就是这个意思。然后,迭代处理进位就行了。如果进位最后还剩下 1 ,那么 append 个 1(翻转后的好处),返回的时候,再翻转回去即可。

这样一段代码,不瞒你说,写了三次才写对。你还能写得比我更差么?

最近,我确实比较闲一点,所以我把十几年前的 WordPress 插件,翻出来重新写,这个过程,虽然没什么价值,但是真的很有乐趣的一件事情,就好像有些人打游戏一样的,你把一个游戏打完了,以前完成得不够好的地方,你就再打一遍,用你以为最完美的形式。写代码,也是一样的。

这是一个面向对象设计的范畴。就像很多网站一样,WordPress 也分为前台和后台,前台是大家看到的博客页面,后台,则是各种控制面板和写作界面。然后,作为 Programmer,你一定会遇到的情况就是,有些代码只属于前台,有些代码只属于后台,而无法避免的就是,有些代码前后台都会用到。这种划分,其实是业务属性层面的划分。

还有一个情况就是,有些代码属于界面布局表现,有些属于后台逻辑计算,有些属于用户交互行为,这是逻辑层面的划分。

我们对这些代码进行分类,无非就是为了更好地去管理复杂性,我们追求的一个方向是高内聚,低耦合,让紧密联系的逻辑尽可能靠近,以加强理解和管理,进而便于去复用。不过,从上面我们也能发现,业务属性的划分和逻辑层面的划分,其实是两个不同的维度,近乎是正交的。

于是,就出现了多种的选择,供 Programmer 去进行决策。我就讲个真实的例子。我在开发一款插件,插件功能是在博客的页面上提供一些官方原本没有的功能,比如,有两个小功能,一个是给每篇文章做一个自动摘要,使得博客首页的文章,总是在一定长度后被截断,不要显示全文,这样即便我忘记进行手动摘要,也可以只显示部分内容,便于读者快速浏览整个博客的内容。另一个功能是,在单篇文章的页面,我们也叫帖子页,展示一个相关文章的列表,展示位置在文章结束的地方,提供一个“相关阅读”的栏目,让读者读完一篇文章的时候,快速发现感兴趣的东西,减少站点跳出。

无论是摘要还是相关文章列表,都是改变前台表现的功能。为了控制这两个功能,我就需要提供不少的用户选项。比如,对于摘要功能来说,怎么控制摘要的长度?文章摘要完毕后,要插入一个链接,引导用户跳转到全文进行查看,这个链接展示的样式,也需要控制,也可能,有用户不喜欢这个功能,需要关闭这个功能,那就需要一个开关。

相关文章的列表的控制项就更多了,列表的长度,是否展示文章的阅读次数或者评论数?列表的标题?或者是否关闭功能。

那么为了控制这些选项,显然,还需要后台选项的调整界面。这就是后台业务逻辑了。

我本来的设计是,有一个 Option Manager,提供所有选项的缺省值管理,选项值的读取,写入,持久化。这样,前台功能的时候,可以通过 Option Manager 访问,后台管理界面也可以。

后来我发现,在这个系统里,实现一个后台管理界面的话,会比较复杂,涉及到很多点,比如后台页面的入口位置,后台表单的呈现,提交后的验证等逻辑。后台交互的组织,非常精巧,所以我就实现了一个抽象类,专门管理后台界面的几个方面,为了控制上面两个功能的选项,我显然要把所有的选项划分成两组去分别管理,后来很自然想到了把所有的缺省值和管理界面放在一起,因为选项的结构和和界面的交互设计,也很有关系,放在一起互相启发和功能调整起来都比较快。

然后我今天重构前台的时候,就发现了很大的困难。因为,为了节省内存,我在判定用户只访问前台的时候,不加载后台的代码,我把选项缺省值,内聚到选项面板的代码里去了,这样,如果用户不访问后台的话,就不加载后台部分代码(为了节省 IO 和 内存),结果前台也读不到选项的缺省值了。

可是如果把选项缺省值抽离到 Option Manager 管理,则管理面板和被管理的选项之间的内聚性就牺牲了,于是我就给自己造就了一个两难的选择。

当然,如果这是我的工作的话,我可能随意选择一个方案就处理了,不会去追求完美,但是我这就是像打游戏一样的心态,肯定是希望对极致能有所追求,于是,这就成为一个有趣的设计问题,完全可以尝试进行一番更为精巧的设计。

感觉我就是很喜欢做这种事情,这才是我的热情所在的地方。要是能找到专门干这种事情就能挣钱谋生的工作岗位,那就完美了。

wordpress

玩 WordPress 年头已经长到记不起最初的记忆了,但是,今天我才发现我对其是何其陌生。

现在的 WordPress 早就不是一个博客软件这么简单了,当年就意识到,WordPress 这样的软件,应该归类到 CMS 系统里面,今天,我才体会到什么叫强大的 CMS 系统。以前目光还是太短浅了,也忽略了事物的发展规律。如果 WordPress 一直把自己定位成一个博客,估计尸骨都凉透了。

最近我把我以前开发的插件拿出来,更新了一些代码,让代码适应现代 PHP 的语法规范,以及适应一下新的 WordPress API,其实,这么做,现在看来已经毫无意义了,只是我实在是太久没写代码了,这么做可能可以让我保持一点感觉,毕竟我是一个 PHP 程序员出身,不能对代码和产品设计毫无感觉。

现如今我的眼光和想法和当年开发插件之初,已经发生了很大的变化。现在回顾当年开发的插件,我发现,代码仍然可以称得上精巧细致,以我现今的眼光看仍然是规范的,没有太多嫌弃年轻时候自己的感觉,只是,我现在更注重规范,一致等等。

但是现今去看当年的功能设计和概念设计,就发现简直不堪入目。比如,把很多明显程序员才了解的概念,公然放在界面上,完全不考虑用户的理解能力,似乎只是骄傲地为程序员做了一些功能。可是这个世界上最广大的用户,根本不是程序员啊?如果我只想服务程序员,又何必去发布插件到官方目录呢?毫无意义嘛,根本不会有人去使用的,就算用了,也根本无从用明白啊。

我用我插件的名字和关键词,搜索插件目录,看看同类品里,做得最好的插件,提供了怎样的功能,以及如何设计交互界面,这才给我打开了一个全新的世界。我发现有些插件的安装量,超过了 500万,这太惊人了,完全超乎了我的想象。虽然我觉得插件的世界是个长尾的世界,但是也没想过有插件能超过 500万安装量。

Gutenberg 古腾堡区块布局

这时候我意识到,我太小看了 WordPress。几个百万级插件的功能,都是围绕了最新的文章编辑器 Gutenberg 的,这个基于 Block 的编辑器,我一直根本就没领悟到精髓啊。其实,Grid 系统,正是最近这些年来页面布局的基础方法,比如 Bootstrap 之类流行世界的框架,都是使用 Grid 系统来布局页面的。这个 Block 编辑器,不就是一个可视化的 Grid 编辑器么?把页面抽象成一行一行的区块,每一行其实也可以切割成两列或者三列,由此形成的 Block 可以用区块编辑器填充各种能想象出来的功能,比如图片,图集,视频,地图,等等。你想做商品展示,或者做成电商店铺,也毫无难点,都有无数高度可视化的插件,让你不懂一点技术的情况下,做出自己想象中的网站,这真是太厉害了!

官方只提供了区块编辑这个框架,丰富的功能,由插件来提供,你可以为整个用户群体发明各种神奇的 block 功能,然后他们就能做出各种匪夷所思的网页来,完全不需要后端程序员,不需要前端程序员,只要自己准备高品质的内容即可。这想法太伟大了,这生态也太牛了。虽然 PC Web 已经没落了,但是,这套体系仍然是兼容移动 Web 的啊!而且还能很好地兼容 PC 和 移动 Web,完全超乎我的想象。

可笑我这么多年,从来没看懂过这些,只是可笑的学了一点编码和前端技术,比起真正的用户价值和商业价值来说,我学到的太少了,比起这个系统能带给客户的商业价值来说,我掌握到的太少了。有种买椟还珠的荒诞感油然而生。可笑一把年纪才明白了这么多浅显的道理,一声叹息啊,与大家共勉。

在 Mac 上安装了 Adobe Photoshop 2021 后,我发现一个代表 Adobe Creative Cloud 服务的图标,出现在 Mac 系统右上角的菜单栏(Menu Bar)上。如果点击这个图标,就会弹出一个窗口,展示 Adobe 的登录表单。这个图标很容易误点,在图标上点击右键,菜单里也没有“退出”选项。打开“系统偏好设置”,“用户与群组”,在“登录项”选项卡上,也没有看到 Adobe 注册什么登录项。到底怎么才能退出这个恼人的程序呢?唯有了解了 launchd 这个系统服务管理机制,才能做到。

Image result for adobe creative cloud icon

Adobe Creative Cloud 的图标

阅读全文 »

从我起心动念开始想要学习 iOS 软件开发到今天为止,已经有差不多四周了。

想要学习手机软件开发的一个原因是我们公司有一个 oa 系统,但是呢,我们现在已经不想使用企业微信,作为扫码登录的一个工具也不想使用企业微信,作为这个系统的消息通道,但是企业微信其实在这方面是非常好用的以至于,那我们并没有合适的替代品,于是我就想到为什么不干脆自己开发一个最简单的 oa 系统的客户端软件呢?

但是其实现在我们公司已经没有养着 iOS 4 团队了,只有一个安卓的开发团队还不是我所在的部门,于是我这个想法并没有相应的开发资源来进行支撑,我就想干脆我自己做算了,我用我的业余时间来开发一个软件给公司的同事们用难道不好吗?

因为我已经连续多年使用苹果手机了,所以呢,我只想学习 iOS 开发对安卓开发没有一点兴趣,另外最近跨平台的开发技术非常的热门,但是拿我也提不起什么性质来,我只是想学习一下苹果手机的开发。

正好呢,最近苹果手机的开发体系发布了一个叫做 SwiftUI 的开发技术框架,于是我就想到嗯嗯,了解一下,没想到一看 SwiftUI 的嗯嗯介绍视频发现嗯这个开发框架非常的友好非常的简洁,而且也十分具有表现力。

于是,我下定决心想要真的学会使用 SwiftUI 去开发一个苹果手机的软件嗯,我的不少朋友都告诉我,SwiftUI 并不是一个特别好的选择应该是在开发到比较高深的功能的时候会遇到很大的阻力,主要是在很多细节的设定上应该是不够灵活的一个框架,但是我想我使用的功能,应该是非常简单的几个功能,我的目标是非常明确的,我只想做这样几个功能:第一,可以进行登录;第二,可以进行扫码登录;第三,可以进行消息,推送;第四,甚至可以实现二次验证登录的这个验证码。至于其他更加复杂的功能,比如说聊天啊,这些都不想实现那么如何在一个 App 里实现 O A 的其他全部功能的当然最简单使用一个 web view 由来嵌入网页的形式。

不过对于我这样一个从来没有学习过苹果手机软件开发的人来说做这样的工作,实在还是太困难了嗯,虽然我懂得开发的基本原理,但是我发现我如果想要完成,我给自己设定的任务,还要学习非常非常多的东西,然后嗯我作为一个资深的程序员,仍然是不能把握住很多重要的东西,因为我以前是一个 web 开发。现在我需要学习的东西,相当于是一个额客户端,软件的开发在性质上差距是非常大的。

今天晚上,我熬到了凌晨 3:00 仍然还无法产生睡意,根本原因就在于我用了一晚上的时间在搜索关于 SwiftUI 相关的开发技术资料,我搜索这些技术资料的根本原因是在于我想要解答,我对 SwiftUI 开发过程中嗯几个疑难的问题。

比如第一个问题就是说一个苹果手机软件,一旦启动了,以后第一个界面会进入到哪里,这个是怎么确定的呢,其实网上嗯,关于这样基本的内容是非常难以搜索到的,因为你如果说关键词是属于 UI 的话,都是在介绍界面怎么布局动画,怎么怎么呈现各种空间如何去设置它?

但是我现在想学的是关于如何构建一个软件基本的流程,而这可能是很古老的 iOS 软件开发的教程里面会提及的内容,但是他涉及到的知识又不是使用 SwiftUI 很有可能是使用最早的 objective c 或者说是 uikit 之类的技术框架。

另外,我想实现一个功能就是嗯用户的登录用户登录以后呢,应该跳转到一个软件的正式界面,但是在用户登录之前是不能直接进入到用户的正式见面了,于是我就想到这其实就相当于是两个完全不同的怎么说呢,就是场景吧,登录是一个场景,正式使用一个软件又是一个场景。如果我们没有登录的话,会应该会被登录界面给挡在外面无法进入到软件的正式操作空间,就这样一个简单的功能,到底应该如何去实现了所有介绍 SwiftUI 的教程视频教程也好文字教程也好都没有提及这个问题。

还有一个我想知道问题,比如说我应该用怎样的布局模式去安排我自己想要的功能,这个也是非常困难的,其实他属于苹果的这种基本交互规范的一个范畴的问题嗯,我按照现在自己的理解参考了企业微信的界面设计,我觉得就应该使用 tabbed view 来实现这个这个界面的布局。但是这个在各种各样的教程里也是没有说的教程,一般只会说,什么样的空间怎样使用,但没有说在什么样的场景下,应该使用什么样的控件。

再有一个问题,就是说我如何,使我的苹果手机软件与互联网上面的各种操作进行有机的结合,比如说我检查一个客户有没有登录到这个手机软件上,那么显然是要通过联网去向服务器确认的,然后我如果手机软件开着,从服务器不断地收到嗯推送过来的消息这个是怎样去实现了市场连接到服务器嗯,然后是服务器推送过来,还是说嗯,是不断地去轮询服务器那样的话大量的客户端软件会不会使服务器造成拥塞,甚至拒绝服务。

随着我对 SwiftUI 表面现象的理解的深入,然后发现更多困扰,我的问题在于如何非常普通的去构建一个苹果手机软件,而不是仅仅使用一个界面开发的框架,我缺乏的是手机客户端软件构建的基本原理的知识。

然而,现在对我来说非常困难,是我根本就不知道从什么样的资料,或者从哪里可以更容易补充到这些客户的软件构建软原理层面基本的知识,互联网上提供的大量的知识都是一种浮于表面性的知识,或者是尝鲜性质的知识,并没有深入到带另一个学习者,逐步深入到一个真正的客观世界的软件的开发过程中。

于是,我就萌生了记录,整个这个过程的一个想法,因为对我来说我是从一个饿一个资深的 web 开发程序员嗯转岗到这个客户端开发程序员,然后从零开始想要构建一个在客观世界中真实有用的,有业务逻辑的苹果手机软件的这样一个场景,那么,如果我能够精细的记录下,我整个过程中的想法,以及我碰的壁以及我找到的学习的路径和方向,那么别人从阅读我的经历的过程中,应该能够得到很多的启发,甚至嗯,从此走上一个正确的道路。

iOS 开发学习,对我来说,最难的并不是语言语法的学习,也不是类库的学习。对我来说,最难的地方,在于资料是零星琐碎而且不成系统的。整个 iOS 开发发展速度太快了。我记得我三周前,第一次打开 Xcode 生成的 Hello World 程序和现在打开再生成的就已经不同了,一些模板文件消失,可见短短三周时间,很多东西已经更新并更换了。

这就导致了一个问题,你能找到的所有的电子书都是过时的。网上找到的关于 SwiftUI 的教程,你照着做一个例子的话,跑不通是大概率的。哪怕是三个月前刚刚出品的视频也是不能避免此点。甚至视频教程里用到的一些类,在你实践的时候,并不存在。

这就导致了,你几乎没有什么东西可以用来直接跟着学习和实践。而真正能找到的学习材料里面,用到了一些基本原理,可能是上一代开发模式里就已经确认的,也可能是上上代就已经确认的,在最新的材料里面,就默认读者已经知道前几代就已经确立了没变的那些原理了,并不会专门去讲解。这就给理解制造了极大的困难。

目前,我找到了一个比较好的能够跟着操作的,就是苹果官方开发网站的 SwiftUI 教程。我已经照着学习了几天了,每天往前做一两个例子,总好过一点也没有前进的好,至少在所有的官方例子实践一遍之前,我还没有卡住过。这是唯一不改一字就可以照着操作的学习资料了。

在学习 SwiftUI Tutorials 的时候,我发现,鼓吹的 Preview 功能,经常有不正常的时候,比如我明明按照例子,什么都写对了,但是就是无法预览,预览的内容始终停留在代码更改之前的样子。我重新 Build 后,仍然解决不了,我不能确认是否代码编写正确。这时候,我如果关掉 Xcode,重新启动后,预览竟然又正常了。重启大法好,对 IDE 都有效。

跟一个五六年前就开始做 iOS 朋友请教一些 Xcode 的用法,他说,SwiftUI 性价比不高,学这个不如学习 Flutter 或者 React,理由是前向兼容性差。估计,他觉得,我作为一个业余选手,如果用不多的时间来学习的话,选择 SwiftUI,可能不太合算吧。至少他们这样职业的开发者,是不会考虑使用 SwiftUI 的,因为可能不兼容老版本的各种设备或者各种系统。

– 至此大概放弃了 –

公司要求每个部门制定事故定级和处罚规定。听那意思是,还是以处罚为主,希望制定出来不同等级的事故的不同处罚。

听说,这个想法来由是,财务团队曾经数次出现疏漏,给公司带来了几个不小的麻烦,所以,想要逼着所有部门都能制定事故分级管理和处罚规定,估计心里想得是希望以此能威慑员工,做事小心不要犯错误。

阅读全文 »

公司大了,内网系统多了,关键性信息和商业秘密也多了以后,内网信息安全就成了很重要的命题,使用各种框架默认带有的类库,直接弄一个简单的用户名密码校验就已经不满足需求了。

设计一个身份验证解决方案就势在必行,当然了,设计一个解决方案,不一定非要自己撸代码,可以对接、购买,关键是看你的需求是什么。当然,我们还是选择了自己实现一个,这可能不是一个很好的选择,要在此声明这一点。

阅读全文 »

今天这道题目真是简单,把一个整数反转了,要考虑负数的情况,如果反转过来溢出了,返回 0,假设的整数是 32位 有符号整数。我写了这样的代码:

1
2
3
4
5
6
7
8
9
class Solution:
def reverse(self, x: int) -> int:
flag = -1 if x < 0 else 1
x = -x if x < 0 else x
res = 0
while x > 0:
res = res * 10 + (x % 10)
x = x // 10
return res * flag
阅读全文 »