《算法新解》读记(一)
这是一本什么书?
最早是在图灵社区看到今年年初这本书的问世,作者刘新宇获得清华大学自动化系学士和硕士学位,长期从事软件研发,关注基本算法和数据结构,尤其是函数式算法,目前就职于亚马逊中国的仓储和物流技术团队。
直到过年期间,和朋友一起逛上海书城,看到了实体书,便随手买了一本。至今也有十来天,稍稍有选择性地读了一点篇章。整体感觉,这本书还是可以用「惊艳」一次来形容的。不同于学生时代我看过的一些面向算法竞赛选手的书籍或者是面向高校学生的数据结构与算法读物,这本书可谓是将两者的特性柔和在了一起,既涵盖了那些经典的数据结构与算法,如红黑树、AVL树、Trie、B树、二叉堆、快速排序、归并排序等,也有一些高级主题如Patricia、后缀树、左偏堆、手指树、斐波那契堆(可怕)等。不过像是90年代发明的跳跃表此书倒是没提及。
相比较传统的使用C/C++, Java这样的命令式编程语言来讲解算法与数据结构,这本书中的主要语言是Haskell。Haskell是一种非常纯的函数式编程语言,在大学的时候选修过,可惜当时这门课是混过去的,完全不敢说会Haskell,只能说能看懂点。
话休烦絮,此书前言直接甩了两道算法题过来让读者见识下算法的威力。
下面就谈谈书中前言介绍的其中一题:
最小可用ID
这题的背景是系统中需要使用非负整数作为ID,用户的ID具有唯一性,系统中有若干ID,需要寻找出一个最小的可以使用的ID。
可能熟悉博弈论的同学都比较容易想到,这个就是SG函数(Sprague-Grundy Function)中的mex运算(minimal excluded)。
此书针对这一问题也给出了多种算法进行比较,由于我工作语言目前是Java而不同于书中的Python或者Haskell,所以下面我会贴出本问题我的Java代码。
朴素解法
朴素解法很容易实现,直接O(n^2),遍历每个自然数,扫描数组,判断是否在数组中,不在则返回答案。此解不需要贴出代码了。
一个线性解法
基于两个事实:1.数组中的元素都是非负整数。 2.答案必然落在[0, n]的区间,其中n为数组长度
所以事实上可以用一个bool数组记录数组中每个数字的出现情况,bool数组的长度可以取n+1,这样的话在原数组刚好包含了某个0到n-1的排列的情况下,也可以归一化处理,而无需特判。
1 public class MinFreeProblemSolver { 2 public static int solve(int[] numbers) { 3 boolean[] occurrence = new boolean[numbers.length]; 4 for (int number : numbers) { 5 if (number < numbers.length) { 6 occurrence[number] = true; 7 } 8 } 9 for (int i = 0; i < numbers.length; i++) { 10 if (!occurrence[i]) { 11 return i; 12 } 13 } 14 return numbers.length; 15 } 16 }
一个更好的线性解法
考虑到在例如Java语言中,通常boolean类型在作为数组时,数组中每个boolean值占用1个字节的空间。实际上对于这样用于标记某个不是太大的非负整数的存在性,可以采用压位存储的方法来节省空间。这样的话一个字节可以存储8个数字的存在性,这节约了相当多的空间。对于C++或者Java,bitset/BitSet已经封装好了标记/清除/翻转/获取某一位的api。
这个东西也被称为位图BitMap,意思差不多。
代码如下。
1 public class MinFreeProblemSolver { 2 public static int solve(int[] numbers) { 3 BitSet occurrence = new BitSet(numbers.length); 4 for (int number : numbers) { 5 if (number < numbers.length) { 6 occurrence.set(number); 7 } 8 } 9 return occurrence.nextClearBit(0); 10 } 11 }
一个基于分治的解法
实际上这个问题也可以通过分治法来解,假设将数组劈成两个子数组A和B,使得数组A的元素都小于等于分割值,假设A中的元素个数是原来数组的长度的一半,则说明需要在B数组中寻找最小可用整数,处理B数组,否则处理A数组。
1 public class MinFreeProblemSolver { 2 public static int solve(int[] numbers) { 3 return solve(numbers, 0, numbers.length - 1); 4 } 5 6 private static int solve(int[] numbers, int fromIndex, int endIndex) { 7 if (fromIndex == endIndex) { 8 return numbers[fromIndex] == fromIndex ? fromIndex + 1 : fromIndex; 9 } 10 int pivot = (fromIndex + endIndex) >>> 1; 11 int left = doPartition(numbers, fromIndex, endIndex, pivot); 12 if (left == pivot + 1) { 13 return solve(numbers, pivot + 1, endIndex); 14 } else { 15 return solve(numbers, fromIndex, pivot); 16 } 17 } 18 19 private static int doPartition(int[] numbers, int fromIndex, int endIndex, int pivot) { 20 int left = fromIndex; 21 for (int right = fromIndex; right <= endIndex; right++) { 22 if (numbers[right] <= pivot) { 23 int temp = numbers[right]; 24 numbers[right] = numbers[left]; 25 numbers[left++] = temp; 26 } 27 } 28 return left; 29 } 30 }
一个更好的分治解法
实际上,上面的基于递归的分治是可以改造为迭代来处理的,用迭代取代递归的优势在于节省递归调用的时间和空间开销,但往往会导致代码的可读性下降。关于使用迭代的解法,由于与递归解法大体相似,不再冗述。
转载于:https://www.cnblogs.com/micrari/p/6413378.html
《算法新解》读记(一)相关推荐
- 《算法新解》作者刘新宇:我只是想打开那些黑盒子,告诉人们里面有什么。
本文章仅用于学习和交流目的,不得用于商业转载.非商业转载请保留原作者.译者.原始链接地址:http://www.ituring.com.cn/article/274001 访谈嘉宾: 刘新宇,于199 ...
- Python爬虫及其它函数知识读记及简单用法,持续更新中...
Python爬虫相关函数知识读记及简单用法,持续更新中- requests [riˈkwests] n. 请求,要求( request的名词复数 ): 需要: 所请求的事物: 申请书 函数或单词- 音 ...
- 图神经网络推荐方向--论文代码读记
前言 这篇作为自己读论文代码过程中一些简单的代码备忘读记吧,方便查阅. 一.torch.cat() .torch.stack() 拼接张量:torch.cat() .torch.stack() tor ...
- 区块链技术六大核心算法,读懂六大核心算法就变成区块链专家
区块链技术六大核心算法,读懂六大核心算法就变成区块链专家 近日,在加密货币经历"混乱时期"后,区块链再次火爆起来,受到了各方的极大关注与重视,成为资本市场和各领域关注的焦点,就连朋 ...
- 我的一年AI算法工程师成长记
作者 | 张怡 来源 | Datawhale(ID:Datawhale) [导语]经常有朋友私信问,如何学python?如何敲代码?如何进入AI行业?正好回头看看自己这一年走过的路,进行一次经验总结. ...
- 算法工程师养成记(附精选面试题)
通往机器学习算法工程师的进阶之路是崎岖险阻的.<线性代数><统计学习方法><机器学习><模式识别><深度学习>,以及<颈椎病康复指南& ...
- 席慕容《写给幸福》读记
年后从家里来的那一天,当坐了十多个小时的硬座车抵达厦门时,天气不算晴朗,但是南方的温暖还是和前一晚刚落完雪的北京有着鲜明的对比.而后转了两趟车才回到学校,那天四点的下午阳光明媚,虽说期间遇到了一个小波 ...
- 【JVM进阶之路】垃圾回收机制和GC算法之三色标记(三)
JVM往期文章 [JVM进阶之路]内存结构(一) [JVM进阶之路]玩转JVM中的对象(二) 上篇文章中讲到JVM中的对象以及判断对象的存活,那么对于"已死"的对象应该如何处理,怎 ...
- 心法利器[55] | 算法工程师读论文思路
心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会,与大家一起成长.具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有. 近期,我再次总结了我的历史文章,累积起来有50w字,百余篇文章了,有兴 ...
- 算法工程师读论文思路
读论文方面的经验,我应该不是第一次写了,之前有关研究生的经验里多少提过一些(我从研究生生活中得到的经验,心法利器[36] | 开学季:我给研究生的建议),但是我们毕业后,走向算法工程师的工位后,持续学 ...
最新文章
- 两张超级大表join优化
- 027_html框架
- jenkins部署java项目(五)
- 如果再写 for 循环,我就锤自己!
- 安装失败java.lang_linux安装jdk出现java/lang/NoClassDefFoundError: java/lang/Object错误的解决方案...
- ASP.NET获取客户端、服务器端基础信息
- 戴尔电脑好还是华为好_华硕和戴尔笔记本哪种好 华硕和戴尔优缺点分析【详解】...
- UnityShader26:运动模糊
- Spark与MR的区别
- Vue 系列二 之 猛龙行动之绝密代码
- 风控每日一问:风控工作的价值在于?
- Keil MDK5工程文件不可修改(文件符号上带一个黄色的钥匙)
- 【主题词——百合花】
- 国产小家电品牌如何用dtc模式打造新中产超爆款?
- Chrome 53 Beta一些有意思的改动
- 最近遇到一个ORA-1000,“maximum open cursors exceeded“
- hadoop最新官网如何下载之前版本(2.7.1)
- java编程 网络大讲堂 pdf_《Java编程网络大讲堂》 闫迎利、王伟平 【正版电子纸书阅读_PDF下载】- 书问...
- IDEA版本和JDK版本对应关系
- 求一元二次方程ax2+bx+c=0的实数根