技术提高是一个循序渐进的过程,所以我讲的leetcode算法题从最简单的level开始写的,然后到中级难度,最后到hard难度全部完。
目前我选择C语言,Python和Java作为实现语言,因为这三种语言还是比较典型的。由于篇幅和精力有限,其他语言的实现有兴趣的朋友请自己尝试。
初级难度说的差不多的时候,我打算再加点其他内容,我可能会从操作系统到协议栈,从分布式聊到大数据框架,从大数据聊到人工智能,... ...。
如果有任何问题可以在文章后评论或者私信给我。
我会持续分享下去,敬请您的关注。
LeetCode 717. 1比特与2比特字符(1-bit and 2-bit Characters)
问题描述:
有两种特殊字符。第一种字符可以用一比特0来表示。第二种字符可以用两比特(10 或 11)来表示。
现给一个由若干比特组成的字符串。问最后一个字符是否必定为一个一比特字符。给定的字符串总是由0结束。
注:
- 1 <= len(bits) <= 1000.
- bits[i] 总是0 或 1.
示例:
C语言实现:
这道题的解法很多,我只列出两个比较简洁的实现方式,性能可能不是最好,但是足够简单。时间复杂度都是O(n)。
第一种方法:
我们看2比特字符的定义,它的起始比特一定是1,而第二个比特是任意的,所以我们很容易得出结论,如果我从数组的起始位置开始遍历:
- 如果遇到元素1,那么它后面的一个元素一定会和结合成一个2比特字符,
- 如果遇到0,那么它一定被作为一个1比特字符;
- 如果遍历结束末尾的0被结合了,那么就应该返回false,否则返回true。
所以我们可以画出如下的步骤图:
原理很简单,代码也同样简单。我们判断末尾0是否被结合,是通过遍历后i的结果来判断的。
第二种方法:
一般我不会给多个算法的源代码,大部分时候仅仅是提供一些思路,今天我会给出的第二种算法会附带源码,因为这种方法也足够简单,可以满足篇幅的要求。
如上图红色标记的0是除去末尾的0元素外,数组的最后一个0元素,这个0元素很关键,我们给它起个名字叫Z,通过观察你会发现:
如果Z前面也是0,那么Z作为一个1比特字符存在;
如果Z前面是1,那么有两种情况:
- 和1组成10,变成一个2比特字符;
- 如果前面的1和还有1,且结合成了11,那么Z将作为1比特字符存在;
综上所述,无论如何,Z都和它后面的元素无关,也就是说它的左边和结果无关,影响结果的只在右边。
此外,因为它是除末尾0元素外的最后一个0元素,也就是说,它后面到末尾0元素间的所有元素都是1,或者不存在任何1元素,所以我们可以得出如图所示的结论:
- 当Z到末尾0之间有奇数个1,则,结果返回false,因为最后一个1会和末尾0结合成一个2比特字符。
- 当Z到末尾0之间有偶数个1,则,结果返回true,因为最后一个1不会和末尾0结合成一个2比特字符。
这个算法的问题是,在一种极端情况下表现可能会不如第一种算法,这种情况就是,Z到末尾0元素间的连续1元素个数特别多,大于数组长度的一半以上。
两种算法在LeetCode上提交,跑出的结果差不多。
python语言的实现:
python的实现用的是上面说描述的第二种算法。
虽然在LeetCode上提交这两种实现表现差不多,但是经过我的评测,第二种算法效率要比第一种算法好很多,第二种算法的的问题是输入数组长度很大时,它的两次切片操作消耗很大,是唯一的瓶颈。
代码如下:
Java语言的实现:
Java 的实现用的是上面描述的第一种算法。
代码如下: