掷骰子和比特币发行量有什么关系

您现在的位置:
现在比特币挖矿难度有多大?哈希碰撞就像掷骰子
  现在比特币挖矿难度有多大?哈希碰撞就像掷骰子
  比特币的产生就是通过不断的碰撞哈希值,谁先碰到了正确答案,谁就能够从中获取一定的货币份额。哈希值的概念本辣条就不详解了,度娘随意就能找到一大把答案。如果你是一名新的矿工,可能你很难想象用CPU来挖矿究竟有多么困难。
  哈希碰撞就像掷骰子
  本辣条当年虽然没能赶上第一波挖矿的浪潮,但是,通过&无线网络安全测试&的过程中,了解到了当年所使用的一款笔记本电脑CPU的哈希值碰撞能力,大概每秒钟有800多次,一块中端显卡大概有2000多次的碰撞能力。如果大家不是很理解这个概念,则可以通过下表来感受下那款笔记本的弱鸡算力和现在算力的惊天难度。
  哈希值碰撞次数单位
  截止至日20:10
  目前全网算力已经达到了5742PH/S之多,也就是5.742EH/S,本辣条在2013年测试的9500 GT显卡算力用沧海一粟的形容好像并不能表达出目前的难度之大,如果可以,本辣条想说万海一粟。在一个月以前,一块GTX 1080的算力运行24小时只能获得越0.1元的比特币收益,那些还在说是因为比特币挖矿直接导致了2017年的显卡市场巨变的某些网站编辑请一定保护好自己的脸,因为现在显卡大部分都用于挖ETH和ZEC。   南方财富网微信号:南财
比特币专区
48小时排行您现在的位置:
现在比特币挖矿难度有多大?哈希碰撞就像掷骰子(2)
  你真的不知道CPU挖矿是有多难
  在挖矿初期,只要随便一台电脑就可以进行挖矿,而且难度极低,用处理器就能很简单的开始工作,虽然CPU的性能强大,但是由于逻辑过于复杂,并不适合简单无脑的巨量工作,而显卡的多处理器特性以及天生适合大量暴力运算等特点,迅速进入业内人士的视野。
  CPU的逻辑过于复杂
  初期还并没有特别强烈的矿工这个概念,大家都是用自己的个人电脑进行挖矿,而比特币也始终只是极客间的潮物,并没有太多人关注。被人们广为熟知的第一笔比特币交易始于2010年,一个叫做拉斯洛的美国人居然用了一万个比特币买了两个披萨。然而现在比特币已经价值超过1.6万元()一个,不知道这位老哥目前是怎样一种心态。
  求这位老兄的心理阴影
  低算力的矿工在每个块里的优势越来越低,只又很小的几率获得份额,于是&矿池&这个神奇的东西就出现了,矿池就是集中大家的算力,相对于算力单薄的其他矿工来说能够有更大的几率出块,大家分得的份额也就更多。
  矿池偷算力是常事儿
  到了后来,用显卡挖矿的方式越来越普遍,被广大矿工们疯抢,造成了从2012年开始的显卡抢购热潮,与现在相比真是有过之而不及,因为矿工们已经经过了一次&矿难&,很多人并没有当年那么疯狂的入场了。如果在那时候就关注这一行业的人,一定知道当年用来挖矿的二手显卡尸横遍野,图吧垃圾佬在捡垃圾的时候也会选择价格极为低廉的矿卡进行攒机。
  南方财富网微信号:南财
比特币专区
48小时排行&p&这几天在准备期末,看了评论,有几个问题&/p&&p&1.这个不是关机代码,没有弹框,关机的是shutdown -s -t &/p&&p&2.报错未找到,不要用汉字命名吧&/p&&p&3.32、64位系统都行&/p&&p&4.进程找不到,杀这个,&/p&&figure&&img src=&https://pic3.zhimg.com/v2-5b837e33138cebfcbcc082d1c2c08536_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&809& data-rawheight=&41& class=&origin_image zh-lightbox-thumb& width=&809& data-original=&https://pic3.zhimg.com/v2-5b837e33138cebfcbcc082d1c2c08536_r.jpg&&&/figure&&p&各系统应该是通用的&/p&&p&5.在下本科学的是食品,有问题大家一起讨论,愿闻指教。&/p&&p&&br&&/p&&hr&&p&笔吧日经问题,是时候把这个搬出来了&/p&&p&Do while(1)&/p&&p&strComputer = &.&&/p&&p&set objWMIService = getobject(&winmgmts:\\.\root\CIMV2&)&/p&&p&Set colProcessList1 = objWMIService.ExecQuery (&Select * from Win32_Process Where Name = '&b&&i&firefox.exe&/i&&/b&'&)&/p&&p&For Each objProcess1 in colProcessList1&/p&&p&objProcess1.Terminate()&/p&&p&Next&/p&&p&Wscript.Sleep(&b&&i&600000&/i&&/b&)&/p&&p&Loop&/p&&p&新建TXT文档,复制粘贴上述,把&b&&i&firefox.exe&/i&&/b&修改为目标程序,名称与进程名一致,&b&&i&600000&/i&&/b&为关闭时间,以ms为单位,例为10分钟,保存,修改后缀为vbs,放入启动文件夹,一般为C:\Users\Master\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup&/p&&p&master是电脑用户名,这个是我的&/p&&p&自己玩的时候结束进程,进任务管理器找,kill&/p&&figure&&img src=&https://pic3.zhimg.com/v2-5b837e33138cebfcbcc082d1c2c08536_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&809& data-rawheight=&41& class=&origin_image zh-lightbox-thumb& width=&809& data-original=&https://pic3.zhimg.com/v2-5b837e33138cebfcbcc082d1c2c08536_r.jpg&&&/figure&&p&寝室关系基本为表面兄弟塑料花姐妹,少花费精力在这些不必要的事情上,哪种解决最快用哪个,&/p&&p&先沟通交流,再次上vbs,最次打他一顿,和谐还是要有的,不然一不小心没控制住明天学校就上头条了。&/p&&p&有其他好办法,望告知。&/p&
这几天在准备期末,看了评论,有几个问题1.这个不是关机代码,没有弹框,关机的是shutdown -s -t 2.报错未找到,不要用汉字命名吧3.32、64位系统都行4.进程找不到,杀这个,各系统应该是通用的5.在下本科学的是食品,有问题大家一起讨论,愿闻指教。 笔吧日…
&figure&&img src=&https://pic1.zhimg.com/v2-31c473b495de5e851a340_b.jpg& data-rawwidth=&752& data-rawheight=&260& class=&origin_image zh-lightbox-thumb& width=&752& data-original=&https://pic1.zhimg.com/v2-31c473b495de5e851a340_r.jpg&&&/figure&&p&这个一个很基础的数学问题,也是一个关于编程的题。实际面试过程中,面对不同岗位,侧重点将会不同。&/p&&blockquote&已知两个正整数 N 和 K,其中 N & = K 且 K & 0&br&如何实现一个函数 sample(N, K),可以从非负整数 [0, N) 中等概率不重复地选择 K 个数&br&当前已知 random(n) 等概率返回 [0, n) 范围内任一非负整数&/blockquote&&p&举个例子,如果 N = 3 且 K = 2,那么 sample(3, 2) 将等概率的返回组合 (0, 1),(0, 2),(1, 2)&/p&&p&&br&&/p&&p&&b&从最简单的实现开始&/b&&/p&&p&从下面这个代码开始看(Java 为例,random(n) -& Random.nextInt(n))&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static int[] sample(int N, int K) {
Random random = new Random();
int result[] = new int[K];
int select = K;
while (select & 0) {
int choose = random.nextInt(N);//随机选一个数
boolean exist =
for (int i = 0; i & K - i++) { //判断这个数是否已经被选择
if (choose == result[i]) {
if (!exist) { // 若没被选择,则加入结果
result[K - select] =
&/code&&/pre&&/div&&p&这个代码的逻辑很直接,不断随机从 [0, N) 中选择一个数字,判断当前该数字是否已经被选择过了,如果没有则加入。重复这个过程,直到 K 个数字全部被选择出来。&/p&&p&这会衍生三个问题&/p&&ol&&li&时间复杂度 &/li&&li&额外的空间复杂度 &/li&&li&等概率证明&/li&&/ol&&p&时间复杂度。代码中可以看到两个循环,外层的 while,内层的 for。for 循环的时间复杂度比较容易得出,至多循环 K 次,也就是 O(K)。while 循环相对就麻烦点,取决于抽样过程中,重复的次数,一个下限 K,那么上限在哪里。理论上可以任意大,每次都抽到同一个数。所以这里需要给出一个平均复杂度,可以根据每次迭代抽到重复数的概率来计算 whlie 循环次数的期望,命名为 O(while)(略:-D,但这很重要)。那么整体的平均时间复杂度就是 O(while) * O(K)。作为一般码农岗,O(while) 最好能给出一个表达式,并不难,也不用太严谨。&/p&&p&额外的空间复杂度。除了结果外,代码中只用了几个额外的基本变量,所以是 O(1)。&/p&&p&等概率证明。题目中要求的不重复可以直接使用”显然易得“。而等概率虽然也非常符合直觉,但如果可以,还是希望给出一些简单的描述,比如每次迭代的时候剩余数字的抽取概率。&/p&&p&&br&&/p&&p&&b&接着上面的代码开始衍生,如何降低平均时间复杂度&/b&&/p&&p&已完成的逻辑,有两个地方比较费时,一个判断是否重复需要 O(K) 的时间,一个重复抽样次数上限不确定。&b&那么有没有办法改进。&/b&&/p&&p&前者把问题引向了&b&如何快速判断集合中某一元素是否存在&/b&。这个大家给出的回答一般比较统一,使用 HashSet / HashMap。涉及到两个操作,一个是 add / put,一个是 exist,对于 HashSet / HashMap 这两个操作都是 O(1),那么判断是否重复的时间复杂度就降到 O(1) 。但这里可能会展开,Java 中的集合类
Map / Set / List 它们的实现类 比如 HashMap / LinkedHashMap / TreeSet / HashSet / LinkedList / ArrayList 它们的具体实现以及各种操作的时间复杂度,以及一些 Java 基础,比如 Comparetor / hashCode / equals 等。一般是不会问特定的 API ,但是数据结构本身会比较关注。 &/p&&p&&br&&/p&&p&另外,如何避免因为重复带来的额外迭代。一般会涉及到变更算法。常规答案很多,比如&/p&&p&&b&用空间换时间&/b&&/p&&p&初始化一个额外 O(N) 空间的 数组 或者 List,来保存剩余数字。每次迭代从数组中随机选择,以避免抽取到重复数字。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static int[] sample(int N, int K) {
Random random = new Random();
int numbers[] = new int[N];
for (int i = 0; i & N; i++) {
numbers[i] =
int result[] = new int[K];
for (int i = 0; i & K; i++) {
int choose = random.nextInt(N - i);
result[i] = numbers[choose];
numbers[choose] = numbers[N - i - 1];
     //已抽取数字换到末尾,或者说将没抽取数字提前
     //这个正确性也有可能会问
&/code&&/pre&&/div&&p&这里时间复杂度为 O(K),但是需要额外的 O(N) 的空间用于储存剩余数字。这是一个典型的时空权衡问题,在这个方向进行深挖,可以进一步降低空间,但基本还是 O(N) 的额外空间,这里可能又需要面试者在数据结构上有一定的能力展示,这是重点。&/p&&p&这个算法对于 N 个数字本身就需要储存的场景非常适用(比如不连续的 N 个数)。但既然是面试流程,很有可能会说当 N 很大的时候,这种算法不可接受。&/p&&p&&b&那么有没有办法,时间复杂度不高又不需要额外的空间&/b&&/p&&p&有,而且还有很多。这里提一个 TAOCP 上经典的算法(其实里面的都很经典),这个如果没看过说不知道,是完全可以理解的事情,这也是很正常的。但是也存在已经给出代码,然后讨论正确性的场景,较为少见。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static int[] sample(int N, int K) {
Random random = new Random();
int result[] = new int[K];
int selection = K, remains = N;
for (int i = 0; i & N; i++) {
if (random.nextInt(remains) & selection) {
result[K - selection] =
selection--;
remains--;
&/code&&/pre&&/div&&p&这个算法的时间复杂度是 O(N),额外的空间复杂度是 O(1),最大的问题是算法的正确性证明不那么直观。主要是两点&/p&&ol&&li&如何保证在 for 循环结束时选择了 K 个数字&/li&&li&[0, N) 中的每个非负整数都是等概率的被选择(无重复性比较明显)&/li&&/ol&&p&对于第一条,这里大家可以先从 N = K & K = 10 手动推一下,会有更直观的认识。每一次迭代 if 都为 true,然后把 i 加入结果,结束时 result 中有 K = 10 个数字。可以证明,算法结束时必然恰好选择了 K 个数字,过程略,^_^(自己动手,丰衣足食)&/p&&p&对于第二条给一个提示。&/p&&p&第一个数字,即 0,只有第一次迭代可能被加入结果,被选中的概率为 K / N(selection = K,remains = N,if 为 true 的概率为 K / N)&/p&&p&第二个数字,即 1,只有第二次迭代可能被加入结果,被选中的概率为 K / N (如果第一个数被选中,概率为 K / N,这时 remains = N - 1,selection = K - 1,1 被选中概率为 (K - 1) / (N - 1)。如果第一个数没被选中,概率为 (N - K) / N,这时 remains = N - 1,selection = K,1被选中的概率为 K / (N - 1)。那么把两者加起来 (K - 1) / (N - 1) * K / N + K / (N - 1) * (N - K) / N,结果为 K / N)&/p&&p&....&/p&&p&最后求得通用表达式,即可证明所有数字是等概率被选择。&/p&&p&算法很稳定,对不同的 K 都可以在线性的时间给出结果,实践中大部分表现良好,而且还是排序好的。这个算法不知道很正常,如果面试官写出来让证明,冷静想想一般多少可以说一点。&/p&&p&&b&不建议背诵该算法,然后啥都说不出了,这个还不如不知道这个算法。&/b&&/p&&p&&br&&/p&&p&前面也说了,既然是面试,保不住会继续问下去。&b&上面这个算法时间复杂度是 O(N),如果 K = 1,还用这个算法,是不是有点浪费。&/b&&/p&&p&这里,首先很直接得让算法中 K 个数选择完了就 break,但是渐进时间没有改变。也可以工程上的考虑,针对不同的 N / K 动态的选择不同的算法,比如 K = 1 的时候就用一开始的算法。但面试官表示,这很好,那还有没有直接点的,一个算法解决的方案。实际是有的,比如下面这个。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static Set&Integer& sample(int N, int K) {
Random random = new Random();
HashSet&Integer& sub = new HashSet&&();
for (int i = N - K; i & N; i++) {
int choose = random.nextInt(i + 1);
if (sub.contains(choose)) {
sub.add(i);
sub.add(choose);
&/code&&/pre&&/div&&p&这个算法的时间复杂度为 O(K),额外的空间复杂度为 O(1),利用了 HashSet 的插入 / 判断存在 时间复杂度皆是 O(1) 的特性,当然 HashSet 本身是有额外空间开销的。&/p&&p&这个算法和上面的一样,不直观,非常不直观,不止是等概率,这次不重复的性质都不明显。&/p&&p&这个地方的重点同样在于正确性证明。&/p&&p&这里对等概率证明给一个提示,计算每个数字被抽取的概率可能比较困难,但是计算每个数字不被抽取的概率要简单点。&/p&&p&如果数字小于等于 N - K&/p&&p&第一个数字,即 0&/p&&p&第一次迭代不被抽取的概率是 (N - K) / (N - K + 1)&/p&&p&第二次迭代不被抽取的概率是 (N - K + 1) / (N - K + 2)&/p&&p&....&/p&&p&最后一次迭代不被抽取的概率是 (N - 1) / N&/p&&p&连乘消项,结果是 (N - K) / N,即被抽取的概率为 K / N &/p&&p&&b&如果数字大于 N - K 了?&/b&&/p&&p&仔细根据 if 条件来计算,稍微复杂一点,结果同样是 K / N。可以先从最简单的,N - 1 (如果 K & 1) 开始计算。过程略,O(∩_∩)O哈哈~(自力更生,丰衣足食 again)&/p&&p&&br&&/p&&p&这个算法同样,如果能写出来,说不出来,还不如不知道。&/p&&p&&br&&/p&&p&--------------------------- 总结的分割线 ---------------------------&/p&&p&基于这个题目,面试流程中,很容易在算法基础和数据结构中发散,所以基础很重要,如果是单纯的背诵对付过去的可能性不大。另外,这个问题会涉及一些简单的概率问题,很多凭借常识都能说出一二,有基本的概率知识就能说得很好,最后两个算法如果没搞懂,面试中说出来容易被问住。若非特定岗,直接说不知道是可以接受的。&/p&&p&这个题目的算法实现有很多,比如的 TAOCP 中专门有一章讲这个,《编程珠玑》也提到过,有时间推荐阅读。其中涉及到的数据结构,建议选择系统化的书籍,偏理论可以看《算法导论》/ 维基百科,具体实现直接看文档,比如 &a href=&https://link.zhihu.com/?target=https%3A//docs.oracle.com/javase/8/docs& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java Platform Standard Edition 8 Documentation&/a&&/p&&p&&br&&/p&&p&-------- 链接的分割线 --------&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&面试经典问题——每次可以走 1 级或 2 级,上 100 级台阶有多少走法&/a& &/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&面试经典问题——统计 32 位&/a&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&有符号&/a&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&整型二进制表示中 1 的数目&/a& &/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&循环不变式,和快速排序算法的多种实现&/a&&/p&
这个一个很基础的数学问题,也是一个关于编程的题。实际面试过程中,面对不同岗位,侧重点将会不同。已知两个正整数 N 和 K,其中 N & = K 且 K & 0 如何实现一个函数 sample(N, K),可以从非负整数 [0, N) 中等概率不重复地选择 K 个数 当前已知 random(n)…
&figure&&img src=&https://pic3.zhimg.com/v2-9d06e01dbc9aa624b8a88b_b.jpg& data-rawwidth=&660& data-rawheight=&416& class=&origin_image zh-lightbox-thumb& width=&660& data-original=&https://pic3.zhimg.com/v2-9d06e01dbc9aa624b8a88b_r.jpg&&&/figure&&p&这个问题经常出现在面试中,无论是作为面试官,还是围观他人面试,甚至被面试的时候都遇到过这个问题,或者说这种问题的变种。&/p&&p&这个问题标准的描述是。&/p&&blockquote&给定一个有 N 级台阶的楼梯,一个人从下到上开始上台阶,这个人有两种上台阶的方式:一次上一个台阶,一次上两个台阶;&br&问:从台阶底端走到到台阶顶端,有多少种上台阶的方式?&/blockquote&&p&举个例子是就是, 3 级台阶。一共有 3 种走法。每次上 1 个台阶连上三次 / 先上 1 个台阶再上 2 个台阶 / 先上 2 个台阶再上 1 个台阶。&/p&&figure&&img src=&http://pic4.zhimg.com/v2-4be400b0f17ef9cc64d5353f_b.jpg& data-size=&normal& data-rawwidth=&784& data-rawheight=&194& class=&origin_image zh-lightbox-thumb& width=&784& data-original=&http://pic4.zhimg.com/v2-4be400b0f17ef9cc64d5353f_r.jpg&&&figcaption&这图好丑&/figcaption&&/figure&&p&遇到这个问题,可以不知道最优解法,但是作为计算机专业方向从业人员。有一个方法是一定要知道的。&/p&&p&&br&&/p&&p&&b&穷举&/b&&/p&&p&写出一个正确的穷举,有个基本的要求——正确的刻画状态转移。有些面试者,可能是紧张,可能确实基础不行,描述一个穷举过程都是错的,不知道当前计算到哪里了,接下来应该计算哪个状态,什么时候结束。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static int sum(int step) { //计算 step 台阶有几种走法
if (step & 0) { //step & 0,非法走法,返回 0
} else if (step == 0) { //最后一步到达起点,返回 1
} else { //接下来如果先走 1 级的走法 + 先走 2 级的走法
return sum(step - 1) + sum(step - 2);
&/code&&/pre&&/div&&p&这是一个简陋的穷举实现,还有很多其他的实现(优化)方式。但是在这个过程中,如果最后没有写出能给出正确结果的逻辑,那么最希望看到的是一个正确描述穷举的过程。比如,使用一个多叉树刻画穷举过程,如下图。&/p&&figure&&img src=&http://pic1.zhimg.com/v2-4de76ebacbcd829eb8bdde_b.jpg& data-size=&normal& data-rawwidth=&402& data-rawheight=&341& class=&content_image& width=&402&&&figcaption&黑色节点代表可行路径,红色节点代表非法路径&/figcaption&&/figure&&p&这里一颗二叉树,因为每次的选择都只有两种可能。事实上,绝大多数穷举都可以很容易的用多叉树的形式表述出来,特别是面试的场合,让人一听就知道你怎么想的。那么可以让人知道至少有正确的思维。&/p&&p&&br&&/p&&p&&b&动态规划&/b&&/p&&p&接下来如果学过动态规划,那么很容易的可以发现这个问题可以归结到子问题的求解上。在递归的思想上,动态规划同样需求对子问题进行正确的划分。但相比朴素递归算法的效率低下,动态规划通过仔细的安排求解顺序,对每个子问题只求解一次,并将结果保存下来。那么随后再次需要此子问题的解的时候,只需要查找保存的结果,而不必重新计算一次。这是一个典型的时空权衡的例子,它在时间上的节省可能非常巨大——可能将一个指数时间的解转化为一个多项式时间的解。&/p&&p&同样的代码&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static int sum(int step) {
if (step & 0) {
} else if (step == 0) {
return sum(step - 1) + sum(step - 2);
&/code&&/pre&&/div&&p&对于 sum(5),它的穷举描述图为&/p&&figure&&img src=&http://pic3.zhimg.com/v2-6aa533b75aa50f743f4a_b.jpg& data-size=&normal& data-rawwidth=&485& data-rawheight=&348& class=&origin_image zh-lightbox-thumb& width=&485& data-original=&http://pic3.zhimg.com/v2-6aa533b75aa50f743f4a_r.jpg&&&figcaption&省略了一些节点&/figcaption&&/figure&&p&可以发现,对于剩余 3 的情况,第三层最左和第二层最右都出现了,在上述的代码里,每次都要重新计算 sum(3)。如果可以在第一次计算 sum(3) 的时候把结果储存下来,那么后续再次计算到 sum(3) 的时候就可以直接返回结果,从而节省大量不必要的计算时间。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static int sum(int step, int mem[]) {
if (step & 0) {
} else if (step == 0) {
} else if (mem[step] != 0) {
return mem[step];
int value = sum(step - 1, mem) + sum(step - 2, mem);
mem[step] =
public static int sum2(int step, int mem[]) {
mem[0] = 1;
mem[1] = 1; //为什么要提前初始化这一项?
for (i = 2; i &= i++) {
mem[i] = mem[i-1] + mem[i-2];
return mem[step];
&/code&&/pre&&/div&&p&这里给出了自顶而下和自底而上两种方法,使用了一个 数组 来储存计算结果(注意 mem 边界,这里感谢 &a class=&member_mention& href=&http://www.zhihu.com/people/de335ad9ea98bc36afd130f& data-hash=&de335ad9ea98bc36afd130f& data-hovercard=&p$b$de335ad9ea98bc36afd130f&&@砒霜拌辣椒&/a& 提出的建议,他认为数组比 HashMap 表达上会更友好)。这个代码本身是存在优化空间,比如在递归中何时判断当前 step 是否存在,是否应该提前把 0 加入 mem 等;在迭代中,mem 真的需要 step + 1 那么大么。&/p&&p&在这个过程中,如果学过动态规划,那么使用这种方法(备忘录)是一件很自然而然的事情,因为子结构实在过于明显。但是在这个过程中,更希望可以看到个人对动态规划的理解,比如什么问题适用于动态规划,什么是最优子结构,什么是自顶而下,什么是自底而上。&/p&&blockquote&《算法导论》 第四部分 高级设计和分析技术,第 15 章 动态规划&/blockquote&&p&建议有时间可以多看一下。&/p&&p&&br&&/p&&p&&b&斐波那契数列&/b&&/p&&p&如果知道这个数列,那么看上面的递归实现,很容易可以发现这就是一个斐波那契数列。N 级台阶的走法对应着 Fibonacci(N + 1) 的值。&/p&&p&那么这个问题就转化为求解斐波那契数列。&/p&&figure&&img src=&http://pic3.zhimg.com/v2-ec76ce78eae2b9b9ddf6ae758e19cf8a_b.jpg& data-caption=&& data-size=&small& data-rawwidth=&660& data-rawheight=&416& class=&origin_image zh-lightbox-thumb& width=&660& data-original=&http://pic3.zhimg.com/v2-ec76ce78eae2b9b9ddf6ae758e19cf8a_r.jpg&&&/figure&&p&实际上斐波那契数列存在通项公式可以直接求解,即使不使用通项公式,也有很多优化算法。有兴趣可以参考这个链接,&a href=&http://link.zhihu.com/?target=https%3A//www.geeksforgeeks.org/program-for-nth-fibonacci-number/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Program for Fibonacci numbers - GeeksforGeeks&/a&。&/p&&p&在这个主题里,其实并不是特别关心斐波那契数列求解有哪些实现,如何优化。所以这个问题在这里就不展开了。但还是建议阅读下链接中的内容。&/p&&p&&br&&/p&&p&--------------------- 题外话的分割线 ---------------------&/p&&p&最后,评论中提到了,int 可以表达 100 级的解么。实际上不能,32 位有符号整型最多表示到 N = 45。那么 long 可以么,或者说当前语言不是 Java,答案又是如何。&/p&&p&另外收到一个私信,有人问&/p&&blockquote&N 级台阶,一次可以走 1 级或者 2 级,但是由于体力有限,如果连续走了 5 次 2 级,就要走 1 级以恢复体力,则有多少种方法?&/blockquote&&p&回复&/p&&blockquote&连续走 5 个 2 级接下来就必须走 1 级,等价于不允许连续出现 6 个 2 级。最朴素的方法,在穷举的递归函数中加上一个参数,代表当前已经连续几次走 2 级了,比如这个参数名为 count。&br&&br&if (count & 5) { return sum(n - 1, 0) + sum(n - 2, count + 1); } &br&else { return sum(n - 1, 0); }&br&&br&这个代码不完整,但是逻辑是这样的。但是这个问题其实可以更深一步,就是是否也适用动态规划,是否同样有递推公式,这里可以肯定说是有的。具体的过程我不写了,因为我认为这样不太好,而且避免你受到我的影响。解决问题从最简单开始考虑,首先是 1 / 2 / 3 / 4 级台阶的答案是什么,可以手算下。然后考虑 n,总结之前的数字。在推 f(n) 的时候,其中遇到什么问题,为什么推不下去。前面递归实现中加入了一个额外的 count,那是不是可以推 f(n, count),然后在推的过程中,这个 count 是不是可以消除掉,递推公式是什么,条件有哪些,边界在哪里。&/blockquote&&p&&b&这篇文章不是希望提供面试背诵材料,而是希望可以在过程中不断思考,文章中的代码有很多可以持续优化的地方,斐波那契数列那个链接中也提了好几种。另外,就像私信中提到那样,问题可以有变种,除了限制连走特定步数,还有把步数从 1 / 2 改为 2 / 3 / 5 或者其他,除了递推公式变了,还会引入可行性证明问题,所以并不是很希望把这个问题和斐波那契数列绑定起来,当然,很多优化方式是通用的,等等。一般而言,如果不是纯粹秀优越的面试,不会找偏题怪题来为难面试者,如果给不了一个准确结果,那么很希望看到思考的过程 / 解决问题的方式。&/b&&/p&&p&&br&&/p&&p&-------- 链接的分割线 --------&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&面试经典问题——如何从非负整数 [0, N) 中等概率不重复地选择 K 个数&/a& &/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&面试经典问题——统计 32 位&/a&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&有符号&/a&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&整型二进制表示中 1 的数目&/a& &/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&&span class=&invisible&&https://&/span&&span class=&visible&&zhuanlan.zhihu.com/p/33&/span&&span class=&invisible&&075895&/span&&span class=&ellipsis&&&/span&&/a&&/p&
这个问题经常出现在面试中,无论是作为面试官,还是围观他人面试,甚至被面试的时候都遇到过这个问题,或者说这种问题的变种。这个问题标准的描述是。给定一个有 N 级台阶的楼梯,一个人从下到上开始上台阶,这个人有两种上台阶的方式:一次上一个台阶,一…
&b&&figure&&img src=&https://pic1.zhimg.com/v2-e408f13afdf3ad54af5b51af_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&40& data-rawheight=&32& class=&content_image& width=&40&&&/figure&&/b&&p&&b&秒懂比特币挖矿:&/b& &/p&&p&&br&&/p&&p&1.我手上现在有一张面值100元的人名币。&b&(比特币)&/b&&/p&&p&&br&&/p&&p&2.谁关注公众号我就给谁。&/p&&p&&br&&/p&&p&3.但是需要在评论里面猜出这张钱的编号才行。&b&(挖矿,随机填充数值求解)&/b&&/p&&p&&br&&/p&&p&自己想尽办法猜,猜中得100元全款——&b&个人挖矿&/b&&/p&&p&&br&&/p&&p&出钱召集一些人来一起猜——&b&矿场&/b&&/p&&p&&br&&/p&&p&召集认识不认识的人一起来猜,通过猜测的次数,按比例分配这100元——&b&矿池&/b&&/p&&p&&br&&/p&&p&以上是一个简单的类比例子,当然,你们关注并猜出了我兜里100块钱的编号,我保证给你。那么,比特币挖矿到底是怎么回事呢?&/p&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-4ab7c23ff1c5c4b8b6bf3_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&60& data-rawheight=&37& class=&content_image& width=&60&&&/figure&&p&&br&&/p&&p&&br&&/p&&p&&b&回顾张三李四转账过程 找出问题&/b&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-2a16b83fb2fe8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1000& data-rawheight=&500& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&https://pic1.zhimg.com/v2-2a16b83fb2fe8_r.jpg&&&/figure&&p&在之前,我们用在一个偏僻的小村张三和李四转账的例子简单解释了什么是比特币。&/p&&p&&br&&/p&&p&没看过的可以看下:&u&&b&&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1MTkwNjg5Mw%3D%3D%26mid%3D%26idx%3D1%26sn%3D4e4db07b5b4bd4a70debac%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&【白话币圈】什么是比特币?这可能是最通俗易懂的答案了&i class=&icon-external&&&/i&&/a&&/b&&/u&&/p&&p&&br&&/p&&p&我们来简单回顾一下:&/p&&p&&br&&/p&&blockquote&当张三想要通过A账号转账1000元给李四的B账号时:&br&&br&&br&① 张三大吼一声:大家注意啦,我用A账号给李四的B账号转1000块钱。&br&&br&② 张三附近的村民听了确实是张三的声音,并且检查张三的A账号是否有足够余额。&br&&br&③ 检查通过后,村民往自己的账本上写:A账号向B账号转账1000元,并修改余额:A账号余额=00元,B账号余额=00元。&br&&br&④ 张三附近的村民把转账告诉较远村民,一传十十传百,直到所有人都知道这笔转账,以此保证所有人账本的一致性。&/blockquote&&p&&br&&/p&&p&聪明如你一定发现了,&b&在步骤② 如果张三吼了一声,附近村民假装没听到,都不去核实记账,那么这个系统不就停止工作了吗?&/b&&/p&&p&&br&&/p&&p&为解决这个问题,村里商讨后决定,&b&谁第一个确认是张三的声音的会获得500元&/b&。于是大家都竖起耳朵,时刻监听村里的每一个动静,真可谓草木皆兵。&/p&&p&&br&&/p&&blockquote&评论区有人问,这500元是哪儿来的?我这里也简答讲一下。&br&&br&1.比特币平均差不多每10分钟产生一个区块,这个区块能打包的交易数量是有限的,我们就算800笔吧。但是呢,旷工不会平白无故给你打包交易到并广播,所以需要收取手续费。而且,由于交易的人很多,先打包谁的交易也取决于手续费的高低。所以你可以看到,现在比特币火热了,手续费水涨船高。&br&&br&2.我们都知道比特币总量2100万个,发币机制是逐年递减。当旷工第一个成功打包这个区块并广播,并且是最长的链的话,那么他还会获得奖励,目前只有12.5个比特币。最开始是50个,已经衰减2次了。这里当然还有小问题,比如为什么要最长链,怎么确定是最长链,哪些链会被抛弃?如果大家有兴趣再深入说说。&br&&br&以上就是旷工的奖励。更新。&/blockquote&&p&&br&&/p&&p&&i&在比特币的世界里,大约平均每10分钟会产生一个区块。所有的挖矿计算机都在尝试打包这个区块并提交,而第一个成功生成这个数据块的人,就可以得到一笔比特币报酬。最初,大约每10分钟就可以产生50个比特币的比特币报酬。但是该报酬每4年减半,现在每10分钟比特币网络就可以产生25个比特币。&/i&&/p&&p&&br&&/p&&p&好了,接着上面的故事讲,张三这一吼,惊动了全村的人,&b&大家都纷纷表示自己是第一个听到张三声音的人&/b&。这500块钱该给谁呢?于是村里又商讨出新的规定,&b&需要有证据证明这是张三的声音&/b&。张三在喊的这一声里带有特定的声波数据,谁先破解出来就给谁。&/p&&p&&br&&/p&&p&在比特币世界里,这是就是一个新的概念,共识机制。&b&比特币是通过工作量证明的共识机制来决定记账权的,通俗来讲,谁证明了自己的工作量最大,谁就负责记账。&/b&&/p&&p&&br&&/p&&p&&i&工作量大小是通过计算符合某一个标准的比特币区块头的哈希散列值来体现的。区块头通常包含前一个区块的哈希散列值、Merkle根、时间戳、难度目标、以及一个填充的随机值。试图争夺记账权的节点称为挖矿节点,&b&挖矿过程就是求出一个能够填充本区块头的随机值,让区块头的哈希散列值符合某一个标准&/b&。&/i&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-d72eb851f8b04ec302beca_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1099& data-rawheight=&810& class=&origin_image zh-lightbox-thumb& width=&1099& data-original=&https://pic3.zhimg.com/v2-d72eb851f8b04ec302beca_r.jpg&&&/figure&&p&咱们接着故事讲,海归村民王二麻子凭借高超的计算能力,成功第一个匹配了张三的声波数据,然后他笑嘻嘻地向全村人广播自己破解成功。村民验证后,王二麻子如愿拿到了500元奖励金,李四也成功收到了张三的转账。&/p&&p&&br&&/p&&p&&i&网络上的每一个矿机接收并验证了一批交易,然后就开始进行挖矿,矿机需要反复的试验随机填充值来进行求解,一般采用产生随机数,尝试把产生的随机数填充到区块头,然后计算哈希。如果计算成功,则挖矿成功,向全网广播挖矿所得,全网节点验证后,把这个区块连接到区块的最上端,并且在全网达成一致。&/i&&/p&&p&&br&&/p&&p&故事还在继续,王二麻子拿到这500元后就想:一个人的计算能力有限,我下次也非常可能不是第一个计算出来。若我改进算法,制造&b&专门匹配这种声波数据的机器&/b&,然后卖机器岂不是能大赚一笔?于是就哼哧哼哧的专研去了,并在不久后面世。(&b&专业矿机&/b&)&/p&&p&&br&&/p&&p&村民蜡笔小明买了一台专业机器,觉得不错。&b&于是大量采购,并找到一个电费低廉的场地&/b&,也请了专人人员来维护。于是,蜡笔小明便每天便看着一笔笔的500元进账。(&b&矿场&/b&)&/p&&figure&&img src=&https://pic3.zhimg.com/v2-88bf2434b5ffe309cc1eba512ce09b36_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&580& data-rawheight=&387& class=&origin_image zh-lightbox-thumb& width=&580& data-original=&https://pic3.zhimg.com/v2-88bf2434b5ffe309cc1eba512ce09b36_r.jpg&&&/figure&&p&村民张小凡也采购了一些机器,可是机器不多,能破解并拿到这500奖励的几率并不大。于是他&b&创建了一个平台,所有有计算能力的人都可以参与进来&/b&。若得到奖励,则&b&按每个人的计算力高低分配奖金&/b&。(&b&矿池&/b&)&/p&&figure&&img src=&https://pic3.zhimg.com/v2-bd60fcf0f46_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1460& data-rawheight=&519& class=&origin_image zh-lightbox-thumb& width=&1460& data-original=&https://pic3.zhimg.com/v2-bd60fcf0f46_r.jpg&&&/figure&&p&&br&&/p&&p&好了,村民的故事差不多就到这里结束了,&b&现在回过头来看文章开始的例子是不是特别形象?&/b&你们可以猜猜谁可能挖矿的最大算力。&/p&&p&&br&&/p&&p&&br&&/p&&b&&figure&&img src=&https://pic4.zhimg.com/v2-9ca671eb825f6d5b1a8d88cc31a33083_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&44& data-rawheight=&30& class=&content_image& width=&44&&&/figure&&/b&&p&&br&&/p&&p&&br&&/p&&p&&b&风险与受益&/b&&/p&&p&&br&&/p&&p&其实,最初的时候,我们用电脑CPU就可以挖到比特币,比特币的创始人中本聪就是用他的电脑CPU挖出了世界上第一个创世区块。当然,&b&现在也可以用家用电脑的CPU、GPU挖矿,只是收益非常低了&/b&。&/p&&p&&br&&/p&&p&&b&CPU挖矿的时代早已过去,GPU挖矿也早已不是主流,现在的比特币挖矿是ASIC挖矿和大规模集群挖矿的时代&/b&。&/p&&p&&br&&/p&&p&回顾挖矿历史,比特币挖矿总共经历了以下&b&五个时代:CPU挖矿→GPU挖矿→FPGA挖矿→ASIC挖矿→大规模集群挖矿
&/b&&/p&&p&&br&&/p&&p&挖矿芯片更新换代的同时,带来的挖矿速度的变化是:&b&CPU(20MHash/s)→GPU(400MHash/s)→FPGA(25GHash/s)→ASIC(3.5THash/s)→大规模集群挖矿(3.5THash/s*X)&/b&&/p&&p&&br&&/p&&p&算力就是计算机每秒产生哈希碰撞的能力,算力越高,挖到比特币的概率越大,挖得比特币也就越多,回报越高。&/p&&p&&br&&/p&&p&然而挖矿的受益并不是稳定且有保障的,电费将成为持续挖矿最大的成本之一,所以,有廉价电力的地方便成了旷工的最爱。&/p&&p&&br&&/p&&p&挖矿的风险不仅于此,16年7月开始,比特币网络发行比特币数量就减半了,即每10分钟,每个区块只包含12.5个比特币,意味着相同算力挖出的比特币也会相应减少。但另一方面,币价也有上升可能。同时还伴随着断电、机器维护折旧等风险。&/p&&p&&br&&/p&&p&&b&最后,给大加介绍一种0风险赚钱的方法:&/b&猜出我兜里100元人民币的编号。哈哈。/逃跑...&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-355ffb3ee26_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&834& data-rawheight=&551& class=&origin_image zh-lightbox-thumb& width=&834& data-original=&https://pic3.zhimg.com/v2-355ffb3ee26_r.jpg&&&/figure&&blockquote&简单回答评论中 &a class=&member_mention& href=&//www.zhihu.com/people/025d3da4e2d& data-hash=&025d3da4e2d& data-hovercard=&p$b$025d3da4e2d&&@诺pro&/a& 的一些疑问,估计也是很多人的疑问:&br&&br&1.目前比特币全部账本信息能很好的保存在一台普通的电脑上,这也是Core他们坚持不扩容的原因之一。另外根据摩尔定律,就算小扩容其实影响不大。&br&&br&2.仅仅降低交易费那么旷工没有动力,交易将更拥堵。当然这里有目前比较认可的取代方案POS。上面说的是挖矿是工作量证明即POW(Proof of Work),而POS的全称Proof of Stake,即股权证明。简单来说,就是一个根据你持有货币的量和时间,给你发利息的一个制度,有利于刺激全部用户参与,更去中心化。&br&&br&3.比特币等加密货币是匿名的,虽然你能看到纪录,但是你不知道是谁,同样你可以有多个匿名账户,中心化的你确定你能保密部分信息?&br&&br&4.不知道你这数据哪里来的,确实现在交易量少,原因很多,有支付场景弱,币价太高,大多数人持币待涨等多种因素。突然想到另一个因素,目前大量的币集中在交易所,很多交易所实际上是虚拟交易,当你要提币的时候才是真实交易,这样也大幅降低了真实交易量。&br&&br&更新&/blockquote&&p&&br&&/p&&p&&br&&/p&&p&&b&本文首发公众号“币行观察”,欢迎关注和交流。&/b&&/p&&p&部分资料参考至&a class=&member_mention& href=&//www.zhihu.com/people/8d00c8d489ef911a245d53bce848c316& data-hash=&8d00c8d489ef911a245d53bce848c316& data-hovercard=&p$b$8d00c8d489ef911a245d53bce848c316&&@徐晓聪&/a& &a class=&member_mention& href=&//www.zhihu.com/people/1d18b899a6d6aae579bb91& data-hash=&1d18b899a6d6aae579bb91& data-hovercard=&p$b$1d18b899a6d6aae579bb91&&@小龟&/a& 在本问题中的回答&/p&
秒懂比特币挖矿: 1.我手上现在有一张面值100元的人名币。(比特币) 2.谁关注公众号我就给谁。 3.但是需要在评论里面猜出这张钱的编号才行。(挖矿,随机填充数值求解) 自己想尽办法猜,猜中得100元全款——个人挖矿 出钱召集一些人来一起猜——矿场 召集…
&figure&&img src=&https://pic2.zhimg.com/v2-0de2220230dac080afdf_b.jpg& data-rawwidth=&561& data-rawheight=&248& class=&origin_image zh-lightbox-thumb& width=&561& data-original=&https://pic2.zhimg.com/v2-0de2220230dac080afdf_r.jpg&&&/figure&&blockquote&阅读本文大约需要233s。&br&各位厨请按照个人 爱好(划掉) 立场进行批判……为什么总感觉又会引战……&/blockquote&&p&今天的主角当然是 Kotlin了(划掉) ,其实应该是 C升。&br&C升呢是一门很牛*的语言。在Windows系统搞的风生水起啊。但是不知道为什么就是有很多人不喜欢呢……果然M$是原罪emmmm&/p&&h2&不好意思我就是要针对C升&/h2&&p&由于先入为主的思想,我还是比较喜欢Java的那种命名方式……对于函数名大写开头十分不感冒。(如果C升连函数都小写开头的话怕是会被当年的Sun公司拿去告了吧2333)&/p&&p&所以我到底想干嘛呢?&/p&&h2&Jetbrains 全家桶 Dark ♂ Fa 好啊&/h2&&ul&&li&在Android Studio中有一个功能……就是当初安卓还不支持Java 8以及lambda写法的时候,打开文件时默认会出现伪lambda折叠……&/li&&li&然后我就想……既然如此我应该可以搞一个东西把函数的首字母大写变得“看起来是小写”。这样看C升代码就顺眼多了。&/li&&li&所以呢,找了一下各种资料……&code&Intellij SDK&/code&提供了&code&FoldingBuilder&/code&这么个东西,专门用来折叠和隐藏展示代码的。我们也借助这个功能来实现我想要的功能&/li&&/ul&&p&可是我什么都不会啊……所以呢我就在bing里面搜索&code&intellij plugin hint folder&/code& 果然还是找到了一些线索。看到了一位大佬。&a href=&http://link.zhihu.com/?target=https%3A//github.com/vkurdin/idea-php-lambda-folding/blob/master/src/ru/vkurdin/idea/php/lambdafolding/LambdaFoldingBuilder.kt& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vkurdin/idea-php-lambda-folding&/a&。&br&用kotlin的高阶函数和链式调用写了将近一百行……我整个人都快被flatMap掉了&/p&&p&好的……我们关注的重点是在plugin.xml配置文件上。&br&这位大佬写的是php的匿名函数转lambda折叠……&/p&&div class=&highlight&&&pre&&code class=&language-xml&&&span&&/span&&span class=&nt&&&extensions&/span& &span class=&na&&defaultExtensionNs=&/span&&span class=&s&&&com.intellij&&/span&&span class=&nt&&&&/span&
&span class=&nt&&&lang.foldingBuilder&/span& &span class=&na&&language=&/span&&span class=&s&&&PHP&&/span& &span class=&na&&implementationClass=&/span&&span class=&s&&&ru.vkurdin.idea.php.lambdafolding.LambdaFoldingBuilder&&/span&&span class=&nt&&/&&/span&
&span class=&nt&&&php.typeProvider2&/span& &span class=&na&&implementation=&/span&&span class=&s&&&ru.vkurdin.idea.php.lambdafolding.StandardCallableArgumentsTypeProvider&&/span&&span class=&nt&&/&&/span&
&span class=&nt&&&php.typeProvider2&/span& &span class=&na&&implementation=&/span&&span class=&s&&&ru.vkurdin.idea.php.lambdafolding.PhpOptionTypeProvider&&/span&&span class=&nt&&/&&/span&
&span class=&nt&&&/extensions&&/span&
&/code&&/pre&&/div&&p&我们也照猫画虎搞一个吧……(其他猫做不到!)其实我也做不到~~~~(&_&)~~~~只能自己复制一个&/p&&div class=&highlight&&&pre&&code class=&language-xml&&&span&&/span&&span class=&nt&&&lang.foldingBuilder&/span& &span class=&na&&language=&/span&&span class=&s&&&C#&&/span& &span class=&na&&implementationClass=&/span&&span class=&s&&&类名&&/span&&span class=&nt&&/&&/span&
&/code&&/pre&&/div&&p&然后问题就来了……C#这个“类型”是不支持的。支持的只有XML,HTML,JSON等几种格式……为此我还到youTrack上发了issue,还没人回答。&br&这个问题先放一边。。&/p&&p&&br&&/p&&h2&功能实现:&/h2&&p&既然这样……那就先把实现的代码功能完善一下吧&br&其实说白了还是正则匹配以及编译原理(喵喵喵?)&/p&&p&我们需要匹配的是一个点,点后面的一个大写字母,以及一个表示函数开始的小括号……&br&一开始我想用正则解决问题的。但是感觉事情没有那个简单。&/p&&p&(其实是我不会正则,只懂&code&\.[A-Z]&/code&然后???水平有限,还得学习一个)&br&还是只能靠自己手撸一个好了。。。&/p&&p&&br&&/p&&h2&需求:&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&输入:字符串
输出:Int类型的List/数组,
用于记录每个调用的函数的大写首字母的位置。
&/code&&/pre&&/div&&p&然后我先开始用的是forEachIndexed来匹配的...但是感觉好像哪里不对劲……果然没考虑好内容会出各种奇怪的bug:比如把&code&using System.xxx&/code&的东西也算进去了……&/p&&div class=&highlight&&&pre&&code class=&language-kotlin&&&span&&/span&&span class=&k&&fun&/span& &span class=&nf&&String&/span&&span class=&p&&.&/span&&span class=&n&&findIndexes&/span&&span class=&p&&():&/span&&span class=&n&&List&/span&&span class=&p&&&&/span&&span class=&n&&Int&/span&&span class=&p&&&{&/span&
&span class=&k&&val&/span& &span class=&py&&list&/span&&span class=&p&&=&/span&&span class=&n&&ArrayList&/span&&span class=&p&&&&/span&&span class=&n&&Int&/span&&span class=&p&&&()&/span&
&span class=&k&&var&/span& &span class=&py&&flag&/span&&span class=&p&&=&/span&&span class=&k&&false&/span&&span class=&p&&;&/span&
&span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&n&&forEachIndexed&/span& &span class=&p&&{&/span& &span class=&n&&index&/span&&span class=&p&&,&/span& &span class=&n&&c&/span& &span class=&p&&-&&/span&
&span class=&k&&when&/span&&span class=&p&&{&/span&
&span class=&n&&c&/span&&span class=&p&&==&/span&&span class=&sc&&'.'&/span&&span class=&p&&-&{&/span&
&span class=&n&&flag&/span&&span class=&p&&=&/span&&span class=&k&&true&/span&
&span class=&p&&}&/span&
&span class=&n&&c&/span&&span class=&p&&.&/span&&span class=&n&&isUpperCase&/span&&span class=&p&&()-&&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span&&span class=&p&&(&/span&&span class=&n&&flag&/span&&span class=&p&&){&/span&
&span class=&n&&list&/span&&span class=&p&&.&/span&&span class=&n&&add&/span&&span class=&p&&(&/span&&span class=&n&&index&/span&&span class=&p&&)&/span&
&span class=&n&&flag&/span&&span class=&p&&=&/span&&span class=&k&&false&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&k&&else&/span&&span class=&p&&-&&/span& &span class=&p&&{&/span&
&span class=&n&&flag&/span&&span class=&p&&=&/span&&span class=&k&&false&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&k&&return&/span& &span class=&n&&list&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&出现把&code&using System.xxx&/code&也算进去了的原因就是已经匹配到了&code&.&/code&以及大写字母,但是把第一个出现的是&code&Main&/code&函数的左括号,所以会把这个也给算进去了。因此如果用正则匹配还要处理掉这样的逻辑。。所以还是手撸一个……(欢迎指正)&/p&&p&&br&&/p&&h2&改进(重构)&/h2&&p&然后呢。。。我试试用while写一下循环……然后感觉while也不适合我。。。还是回归到for循环中……并且把&code&when{}&/code&,改用回了那种形式。&/p&&div class=&highlight&&&pre&&code class=&language-kotlin&&&span&&/span&&span class=&k&&fun&/span& &span class=&nf&&String&/span&&span class=&p&&.&/span&&span class=&n&&findIndexes&/span&&span class=&p&&():&/span& &span class=&n&&List&/span&&span class=&p&&&&/span&&span class=&n&&Int&/span&&span class=&p&&&&/span& &span class=&p&&{&/span&
&span class=&k&&val&/span& &span class=&py&&list&/span& &span class=&p&&=&/span& &span class=&n&&ArrayList&/span&&span class=&p&&&&/span&&span class=&n&&Int&/span&&span class=&p&&&()&/span&
&span class=&k&&var&/span& &span class=&py&&findDot&/span& &span class=&p&&=&/span& &span class=&k&&false&/span&
&span class=&k&&var&/span& &span class=&py&&findUpperCase&/span& &span class=&p&&=&/span& &span class=&k&&false&/span&
&span class=&k&&var&/span& &span class=&py&&tempIndex&/span& &span class=&p&&=&/span& &span class=&m&&0&/span&
&span class=&k&&for&/span& &span class=&p&&(&/span&&span class=&n&&i&/span& &span class=&k&&in&/span& &span class=&k&&this&/span&&span class=&p&&.&/span&&span class=&n&&indices&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&k&&when&/span& &span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&[&/span&&span class=&n&&i&/span&&span class=&p&&])&/span& &span class=&p&&{&/span&
&span class=&c1&&//出现点的时候干脆接着判断下一个字符是不是大写字母&/span&
&span class=&sc&&'.'&/span& &span class=&p&&-&&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&findDot&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&findUpperCase&/span& &span class=&p&&=&/span& &span class=&k&&false&/span&
&span class=&p&&}&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&k&&this&/span&&span class=&p&&[&/span&&span class=&n&&i&/span& &span class=&p&&+&/span& &span class=&m&&1&/span&&span class=&p&&].&/span&&span class=&n&&isUpperCase&/span&&span class=&p&&())&/span& &span class=&p&&{&/span&
&span class=&n&&findUpperCase&/span& &span class=&p&&=&/span& &span class=&k&&true&/span&
&span class=&n&&tempIndex&/span& &span class=&p&&=&/span& &span class=&n&&i&/span& &span class=&p&&+&/span& &span class=&m&&1&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&c1&&//出现左括号来判断是否处于判断状态。。。&/span&
&span class=&sc&&'('&/span& &span class=&p&&-&&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&findUpperCase&/span& &span class=&p&&&&&/span& &span class=&n&&tempIndex&/span& &span class=&p&&!=&/span& &span class=&p&&-&/span&&span class=&m&&1&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&list&/span&&span class=&p&&.&/span&&span class=&n&&add&/span&&span class=&p&&(&/span&&span class=&n&&tempIndex&/span&&span class=&p&&)&/span&
&span class=&n&&findUpperCase&/span& &span class=&p&&=&/span& &span class=&k&&false&/span&
&span class=&n&&findDot&/span& &span class=&p&&=&/span& &span class=&k&&false&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&c1&&//出现空格分号以及换行回车字符则判断终止……(你见过C升有哪个函数名字中间还能带空格带分号带回车的?)&/span&
&span class=&sc&&' '&/span&&span class=&p&&,&/span& &span class=&sc&&';'&/span&&span class=&p&&,&/span& &span class=&sc&&'\n'&/span&&span class=&p&&,&/span& &span class=&sc&&'\r'&/span& &span class=&p&&-&&/span& &span class=&p&&{&/span&
&span class=&n&&findDot&/span& &span class=&p&&=&/span& &span class=&k&&false&/span&
&span class=&n&&tempIndex&/span& &span class=&p&&=&/span& &span class=&p&&-&/span&&span class=&m&&1&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&k&&return&/span& &span class=&n&&list&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&然后完工。我们用TEXT文件测试一些结果……至少能用了……&/p&&p&现在来解决Intellij插件的C#的问题……&br&首先是我去提了个问题……还是没人回答。但是我发现我可以用自己写的类型来当C#。尽管这个C#是不能用的那种……&/p&&p&从插件的运行结果上来看。获取的类名是&code&com.jetbrains.rider.ideaInterop.fileTypes.csharp.CSharpLanguage&/code&这么个东西……&/p&&p&&br&&/p&&h2&我有一个大胆的想法&/h2&&p&&br&&br&我就给你创建这么一个包名来造一个C#的类,为了让xml文件能够找得到C#这门语言……至于其他相关的东西在运行过程中是有的,唯独xml文件是找不到语言。&/p&&p&反编译一下CSharpLanguage这个类……&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kn&&package&/span& &span class=&nn&&com.jetbrains.rider.ideaInterop.fileTypes.csharp&/span&&span class=&o&&;&/span&
&span class=&kn&&import&/span& &span class=&nn&&com.jetbrains.rider.ideaInterop.fileTypes.RiderLanguageBase&/span&&span class=&o&&;&/span&
&span class=&kn&&import&/span& &span class=&nn&&kotlin.Metadata&/span&&span class=&o&&;&/span&
&span class=&nd&&@Metadata&/span&&span class=&o&&(&/span&
&span class=&n&&mv&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&&span class=&mi&&1&/span&&span class=&o&&,&/span& &span class=&mi&&1&/span&&span class=&o&&,&/span& &span class=&mi&&7&/span&&span class=&o&&},&/span&
&span class=&n&&bv&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&&span class=&mi&&1&/span&&span class=&o&&,&/span& &span class=&mi&&0&/span&&span class=&o&&,&/span& &span class=&mi&&2&/span&&span class=&o&&},&/span&
&span class=&n&&k&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&o&&,&/span&
&span class=&n&&d1&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&&span class=&s&&&\u\n\u\u0002\n\u\u0002\n\u0002\b\u0002\n\u\u000b\n\u0000\bAE\u\u0\u0001B\u0007\b\u0002?\u\uJ\b\u\u001a\u0H\u0016¨\u&&/span&&span class=&o&&},&/span&
&span class=&n&&d2&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&&span class=&s&&&Lcom/jetbrains/rider/ideaInterop/fileTypes/csharp/CSharpL&&/span&&span class=&o&&,&/span& &span class=&s&&&Lcom/jetbrains/rider/ideaInterop/fileTypes/RiderLanguageB&&/span&&span class=&o&&,&/span& &span class=&s&&&()V&&/span&&span class=&o&&,&/span& &span class=&s&&&isCaseSensitive&&/span&&span class=&o&&,&/span& &span class=&s&&&&&/span&&span class=&o&&,&/span& &span class=&s&&&rider&&/span&&span class=&o&&}&/span&
&span class=&o&&)&/span&
&span class=&kd&&public&/span& &span class=&kd&&final&/span& &span class=&kd&&class&/span& &span class=&nc&&CSharpLanguage&/span& &span class=&kd&&extends&/span& &span class=&n&&RiderLanguageBase&/span& &span class=&o&&{&/span&
&span class=&kd&&public&/span& &span class=&kd&&static&/span& &span class=&kd&&final&/span& &span class=&n&&CSharpLanguage&/span& &span class=&n&&INSTANCE&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&kt&&boolean&/span& &span class=&nf&&isCaseSensitive&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&kc&&true&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&nf&&CSharpLanguage&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&kd&&super&/span&&span class=&o&&(&/span&&span class=&s&&&C#&&/span&&span class=&o&&,&/span& &span class=&s&&&CSHARP&&/span&&span class=&o&&);&/span&
&span class=&n&&INSTANCE&/span& &span class=&o&&=&/span& &span class=&o&&(&/span&&span class=&n&&CSharpLanguage&/span&&span class=&o&&)&/span&&span class=&k&&this&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&static&/span& &span class=&o&&{&/span&
&span class=&k&&new&/span& &span class=&n&&CSharpLanguage&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&明眼人一下就看出来了,这是用Kotlin写的……而且是用的object关键字。但是……我自己亲自创建一个Kotlin的类还是不能被xml调用……那我就创一个Java类吧(不然src/main的java目录空着也不好)&/p&&p&&br&&/p&&h2&【怎么有种狐假虎威的感觉】&/h2&&p&类名随便起也是没事的……主要还是注册C#比较重要&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kn&&package&/span& &span class=&nn&&com.jetbrains.rider.ideaInterop.fileTypes.csharp&/span&&span class=&o&&;&/span&
&span class=&kn&&import&/span& &span class=&nn&&com.jetbrains.rider.ideaInterop.fileTypes.RiderLanguageBase&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&CSharpLang&/span& &span class=&kd&&extends&/span& &span class=&n&&RiderLanguageBase&/span& &span class=&o&&{&/span&
&span class=&kd&&protected&/span& &span class=&nf&&CSharpLang&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&kd&&super&/span&&span class=&o&&(&/span&&span class=&s&&&C#&&/span&&span class=&o&&,&/span& &span class=&s&&&CSHARP&&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&public&/span& &span class=&kt&&boolean&/span& &span class=&nf&&isCaseSensitive&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&kc&&true&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&然后我就可以plugin.xml的文件里面愉快地用C#了……&br&完工。。&/p&&p&&br&&/p&&h2&FLAG&/h2&&p&目前大概欠了两篇Kotlin协程文章。手头上自己玩的项目ktnl、手撸json解析 以及 务正业的开发(所以我一直都是在不务正业……)&/p&&p&&br&&/p&&h2&你学会了什么?&/h2&&p&你学会了挑刺,学会了瞎扯,以及开发了一个十分鸡肋的插件。&/p&
阅读本文大约需要233s。 各位厨请按照个人 爱好(划掉) 立场进行批判……为什么总感觉又会引战……今天的主角当然是 Kotlin了(划掉) ,其实应该是 C升。 C升呢是一门很牛*的语言。在Windows系统搞的风生水起啊。但是不知道为什么就是有很多人不喜欢呢……果…
&p&首先,给一些链接,大多是早年我写的:&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/zhoufoxcn/article/details/4930566& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&请不要做浮躁的人--转给即将上路或者正在路上的程序员朋友 - CSDN博客&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/zhoufoxcn/article/details/1644726& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&一才难求--也谈程序员素质问题 - CSDN博客&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/zhoufoxcn/article/details/3536754& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&asp.net夜话之程序人生 - CSDN博客&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/zhoufoxcn/article/details/4599978& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&与一个即将毕业的计算机系大四学生关于求职的对话 - CSDN博客&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&//link.zhihu.com/?target=http%3A//blog.csdn.net/zhoufoxcn/article/details/5652166& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&工作经验到底是个什么东东?工作经验从哪里来? - CSDN博客&i class=&icon-external&&&/i&&/a&&/p&&p&&br&&/p&&p&其中部分摘抄:&/p&&p&对于即将走出校门或者刚刚走出校门的朋友来说,我建议首先确定一下自己想在哪个城市找工作,虽然很多时候经常有人说语言只是一种实现思想的工具、编程语言没有高低之分,学好哪种语言都能挣钱,但是由于某些原因某些城市里某种语言就比较好找工作,在某些城市里就没有那么明显,比如某个城市大部分是做外包的那可能用Java比较多,如果你是学C#的建议暂不考虑去那里找工作。选定一门编程语言之后,对于同一门编程语言还可以细分的,比如可以分为普通应用软件、嵌入式开发还有Web开发,每种开发需要的知识也不大一样,比如做嵌入式开发就不怎么关注数据库这方面的知识,需要对算法和性能分析方面了解多一些,而做Web开发就需要了解HTML、CSS、JavaScript、Ajax以及数据库等方面的知识。我建议当你确定要在哪个城市找工作之后,你去一些招聘网站上看看这个城市里的软件公司的招聘要求,比如大部分公司的招聘岗位是做什么的,主要用些什么数据库等等之类的,这样做到有的放矢,把有限的时间用在刀刃上。这样去面试的时候就比编程技术和你差不多的人多了一份胜算了。目前比较流行就是Java和C#了,搞偏重于硬件方面的开发就需要学好C、C++及汇编了,用到的数据库主要是SQL Server和Oracle及MySQL。&/p&
首先,给一些链接,大多是早年我写的:
&figure&&img src=&https://pic1.zhimg.com/v2-6c82f56274bcc0b0351db_b.jpg& data-rawwidth=&352& data-rawheight=&220& class=&content_image& width=&352&&&/figure&&p&我们在网上下载软件的时候,上面经常会附加一个 MD5 值。那么这个 MD5 是什么呢?又起到什么作用呢?&br&&/p&&p&一起跟我来看看吧。&/p&&br&&br&&h2&1. MD5 是什么&br&&/h2&&p&全称为&strong& 消息摘要算法版本5 (Message Digest&/strong& &strong&Algorithm 5)&/strong&&br&&/p&&p&它是一种 Hash 算法。&br&&/p&&p&作用是为了信息安全。&br&&/p&&p&再具体点,MD5 值就是一串 128 bit 的数据。&br&&/p&&p&MD5 的核心是通过算法把任意长度的原始数据映射成128 bit 的数据。这一点跟CRC 类似,都是把一串数据经过处理,得到另一个固定长度的数据。(所以讲完 CRC,我要讲 MD5, 因为它们两个在实际中经常会出现和用到。)&br&&/p&&p&MD5 的特点:&/p&&p&不可逆性 --- 根据 MD5 值计算不出原始数据&/p&&p&唯一性 --- 不同原始数据会有不同的 MD5 值 (不完全可靠,后面说)&br&&/p&&p&MD5 到底算不算加密算法?仁者见仁智者见智吧。说它是加密,因为它确实把原始数据,比如用户密码,变成了一般人看不懂的 MD5 值;说它不是加密,因为它不能解密。&br&&/p&&p&据说 Linux 系统中,用户密码,都是以 MD5 形式存在文件中的,这样你在输入密码的时候,计算机只要计算你输入密码的 MD5 再跟计算机文件中存储的 MD5 进行比对就行了。&/p&&br&&br&&h2&2. MD5 算法&br&&/h2&&p&第一步:数据填充。填充后数据长度为 512 bit 的整数倍。&/p&&p&&figure&&img src=&https://pic2.zhimg.com/v2-2ead3b0f632ddf8c802039_b.jpg& data-rawheight=&413& data-rawwidth=&777& class=&origin_image zh-lightbox-thumb& width=&777& data-original=&https://pic2.zhimg.com/v2-2ead3b0f632ddf8c802039_r.jpg&&&/figure&第二步: 循环计算。每 512 bit 作为一组,前一个分组得到的 MD5 作为下一个 分组的状态输入 (看作就是ABCD 吧,代表 4 个 32 bit)。最终的ABCD 就是128 bit 的 MD5。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-5cbd288b61fbb52ac3dd7ad_b.jpg& data-rawheight=&423& data-rawwidth=&631& class=&origin_image zh-lightbox-thumb& width=&631& data-original=&https://pic3.zhimg.com/v2-5cbd288b61fbb52ac3dd7ad_r.jpg&&&/figure&&br&&p&具体的计算过程比较复杂,这里不细说了,说多了大家看起来比较吃力。上面两幅图已经说明了大体的流程。&/p&&br&&br&&h2&3. Hash 碰撞&br&&/h2&&p&Hash 碰撞是指两份不同的原始数据,得到相同的 MD5 值。&/p&&p&我前面已经提到,MD5 是具有唯一性的,其实---这个唯一性是有限的,有概率的。&/p&&p&MD5 之所以应用这么广泛,就是因为它的可靠性,很难有两个不同的输入,得到相同的 MD5。但是!!!虽然概率低 (具体有多大概率,我还没研究清楚),但是确实有。&/p&&p&2004 年山东大学的王晓云就破解了 MD5, 找到了 Hash 碰撞。&/p&&br&&p&其实,Hash 碰撞还是小概率事件了,要不然为何如今尽管已经有人破解了 MD5, 但它还是被大家屁颠屁颠的用着呢?&/p&&br&&br&&br&&br&&blockquote&&p&&b&欢迎关注我的微信公众号:红猴子&/b&&/p&&p&这是一个工科生涨知识的号,公众号的内容有CS\EE技术, 职场以及经验谈,知乎专栏文章会首发于我的微信公众号,希望能给迷茫和困惑中的朋友一些启发与帮助,欢迎围观&/p&&/blockquote&
我们在网上下载软件的时候,上面经常会附加一个 MD5 值。那么这个 MD5 是什么呢?又起到什么作用呢? 一起跟我来看看吧。 1. MD5 是什么 全称为 消息摘要算法版本5 (Message Digest Algorithm 5) 它是一种 Hash 算法。 作用是为了信息安全。 再具体点,MD…
&p& 好像很多人认为我是在说“C# 垃圾”,然后告诉我什么不该抠内存……果然结尾加的话灵验了……我实在不想争论什么 C# 好不好之类的东西,如果你持有这种观点,我承认我是傻逼,请不要评论。&/p&&ul&&li&分配内存于无形&/li&&/ul&&p&典型 API:Encoding.GetString/BitsConverter/Split&/p&&p&这类 API 的特征就是无论如何都会在函数内部去分配这个内存,内存根本无法重用。object.ToString() 其实也有同样的问题:强行分配出一个 string,然后再用这个临时的 string 去和其它的拼接。我认为理想的 API 应该是 void ToString(StringBuilder)。IFormatProvider 也是一样的问题:&/p&&div class=&highlight&&&pre&&code class=&language-csharp&&&span&&/span&&span class=&k&&public&/span& &span class=&kt&&string&/span& &span class=&nf&&Format&/span&&span class=&p&&(&/span&&span class=&kt&&string&/span& &span class=&n&&fmt&/span&&span class=&p&&,&/span& &span class=&kt&&object&/span& &span class=&n&&arg&/span&&span class=&p&&,&/span& &span class=&n&&IFormatProvider&/span& &span class=&n&&formatProvider&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&这里的接受的 fmt,返回的 string,都是无谓的内存分配,理想的接口应该是:&/p&&div class=&highlight&&&pre&&code class=&language-csharp&&&span&&/span&&span class=&k&&public&/span& &span class=&k&&void&/span& &span class=&nf&&Format&/span&&span class=&p&&(&/span&&span class=&n&&StringBuilder&/span& &span class=&n&&builder&/span&&span class=&p&&,&/span& &span class=&n&&IReadOnlySpan&/span&&span class=&p&&&&/span&&span class=&kt&&char&/span&&span class=&p&&&&/span& &span class=&n&&fmt&/span&&span class=&p&&,&/span& &span class=&kt&&object&/span& &span class=&n&&arg&/span&&span class=&p&&,&/span& &span class=&n&&IFormatProvider&/span& &span class=&n&&formatProvider&/span&&span class=&p&&)&/span&
&/code&&/pre&&/div&&p&而对于 Split,我认为理想的返回值类型是 IEnumerable&IReadOnlySpan&char&&。&/p&&p&像 C++ 标准库就很少有这样的问题,因为标准库对于动态内存分配十分谨慎。不过幸好 .NET Core 2.1 要迎来一大波基于 Span 的 API[1]。&/p&&p&还有更恐怖的 boxing,那才真的是分配内存于无形。典型的如 string.Format 装箱满天飞。&/p&&ul&&li&抽象与性能&/li&&/ul&&p&典型:System.Linq&/p&&p&System.Linq 很多时候也会在背地里发生很多内存分配。举个例子,Enumerable.Reverse 会把整个 Source 拷贝进分配的 buffer 里,然后 reverse[2];再例如 Enumerable.Except[3],会在内部分配一个 Set&T&,将 source 的内容全部添加进去。另一方面,基本的 Select、Where 根本优化不掉,虚函数满天飞,性能直线下降。而 C++ 的 range-v3、Rust 的 Iterator 可以做到 Zero cost Abstraction,使用这些设施和裸写循环效果一致[4]。&/p&&p&另外如果你看过 JIT 后的代码就会发现 foreach (var v in list) 根本优化不掉,会按部就班地调用 GetEnumerator、Dispose 等。(foreach Array、string 会在 Roslyn 层翻译为 for (int i = 0; i & .C ++i))[5]。&/p&&p&而且令人震惊的是,使用 where new() 也会造成性能损失[6]!&/p&&ul&&li&歪路&/li&&/ul&&p&C# 自从脱离了 Anders 就已经失去了控制。加一些 readonly ref conditional ref 这些不明所以的玩意[7],真的是冲着 C++++ 努力啊。最关键的 Source Generator[8] (最有用的 feature,没有之一)无人问津,令人失望。&/p&&ul&&li&杂项……&/li&&/ul&&p&.NET Core 2.0 的一些 API .NET Framework 4.7.1 没有,印象深的是 Dictionary.TryAdd。而且 List.ForEach/Find/FindIndex 真的是不明所以……&/p&&p&using 比起 C++ 的 RAII 真的是小巫见大巫。&/p&&p&&br&&/p&&p&千万别跟我说 C# 的 GC 多牛逼不在乎这些,也别跟我说不该在乎这“点”性能。&/p&&p&&br&&/p&&p&[1] &a href=&http://link.zhihu.com/?target=https%3A//github.com/dotnet/corefx/issues/21281& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Add initial Span/Buffer-based APIs across corefx · Issue #21281 · dotnet/corefx&/a&&/p&&p&[2] &a href=&http://link.zhihu.com/?target=https%3A//github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Reverse.cs& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dotnet/corefx&/a&&/p&&p&[3] &a href=&http://link.zhihu.com/?target=https%3A//github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/Except.cs& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dotnet/corefx&/a&&/p&&p&[4] &a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&看看所谓的 Zero cost abstraction&/a&&/p&&p&[5] &a href=&http://link.zhihu.com/?target=https%3A//github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs%23L362& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dotnet/roslyn&/a&&/p&&p&[6] &a href=&http://link.zhihu.com/?target=https%3A//blogs.msdn.microsoft.com/seteplia//dissecting-the-new-constraint-in-c-a-perfect-example-of-a-leaky-abstraction/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Dissecting the new() constraint in C#: a perfect example of a leaky abstraction&/a&&/p&&p&[7] &a href=&http://link.zhihu.com/?target=https%3A//github.com/dotnet/csharplang/issues%3Fq%3Dis%253Aopen%2Bis%253Aissue%2Bmilestone%253A7.2& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dotnet/csharplang&/a&&/p&&p&[8] &a href=&http://link.zhihu.com/?target=https%3A//github.com/dotnet/roslyn/blob/master/docs/features/generators.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&dotnet/roslyn&/a&&/p&
好像很多人认为我是在说“C# 垃圾”,然后告诉我什么不该抠内存……果然结尾加的话灵验了……我实在不想争论什么 C# 好不好之类的东西,如果你持有这种观点,我承认我是傻逼,请不要评论。分配内存于无形典型 API:Encoding.GetString/BitsConverter/Split…
&figure&&img src=&https://pic3.zhimg.com/v2-6a55a7facfd5b1a_b.jpg& data-rawwidth=&1024& data-rawheight=&683& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic3.zhimg.com/v2-6a55a7facfd5b1a_r.jpg&&&/figure&&blockquote&不论是经验丰富的老程序员,还是没有经验的新手,Python 都是一个非常好的编程语言。&/blockquote&&p&&br&&/p&&p&&a href=&https://link.zhihu.com/?target=https%3A//www.python.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Python&/a& 是一个非常流行的编程语言,它可以用于创建桌面应用程序、3D 图形、视频游戏、甚至是网站。它是非常好的首选编程语言,因为它易于学习,不像一些复杂的语言,比如,C、 C++、 或 Java。 即使如此, Python 依然也是强大且健壮的,足以创建高级的应用程序,并且几乎适用于所有使用电脑的行业。不论是经验丰富的老程序员,还是没有经验的新手,Python 都是一个非常好的编程语言。&/p&&h2&&b&安装 Python&/b&&/h2&&p&在学习 Python 之前,你需要先去安装它:&/p&&p&&b&Linux: &/b&如果你使用的是 Linux 系统, Python 是已经包含在里面了。但是,你如果确定要使用 Python 3 。应该去检查一下你安装的 Python 版本,打开一个终端窗口并输入:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&python3 -V
&/code&&/pre&&/div&&p&如果提示该命令没有找到,你需要从你的包管理器中去安装 Python 3。&/p&&p&&b&MacOS:&/b& 如果你使用的是一台 Mac,可以看上面 Linux 的介绍来确认是否安装了 Python 3。MacOS 没有内置的包管理器,因此,如果发现没有安装 Python 3,可以从 &a href=&https://link.zhihu.com/?target=https%3A//www.python.org/downloads/mac-osx/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&python.org/downloads/mac-osx&/a& 安装它。即使 macOS 已经安装了 Python 2,你还是应该学习 Python 3。&/p&&p&&b&Windows:&/b& 微软 Windows 当前是没有安装 Python 的。从 &a href=&https://link.zhihu.com/?target=https%3A//www.python.org/downloads/windows& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&python.org/downloads/windows&/a& 安装它。在安装向导中一定要选择 &b&Add Python to PATH&/b& 来将 Python 执行程序放到搜索路径。&/p&&h2&&b&在 IDE 中运行&/b&&/h2&&p&在 Python 中写程序,你需要准备一个文本编辑器,使用一个集成开发环境(IDE)是非常实用的。IDE 在一个文本编辑器中集成了一些方便而有用的 Python 功能。IDLE 3 和 NINJA-IDE 是你可以考虑的两种选择:&/p&&h2&&code&IDLE 3&/code&&/h2&&p&Python 自带的一个基本的 IDE 叫做 IDLE。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-ba87adffdd1e071b7a825cd_b.jpg& data-size=&normal& data-rawwidth=&446& data-rawheight=&514& class=&origin_image zh-lightbox-thumb& width=&446& data-original=&https://pic1.zhimg.com/v2-ba87adffdd1e071b7a825cd_r.jpg&&&figcaption&IDLE&/figcaption&&/figure&&p&&br&&/p&&p&它有关键字高亮功能,可以帮助你检测拼写错误,并且有一个“运行”按钮可以很容易地快速测试代码。&/p&&p&要使用它:&/p&&ul&&li&在 Linux 或 macOS 上,启动一个终端窗口并输入 &code&idle3&/code&。&/li&&li&在 Windows,从开始菜单中启动 Python 3。&/li&&ul&&li&如果你在开始菜单中没有看到 Python,在开始菜单中通过输入 &code&cmd&/code& 启动 Windows 命令提示符,然后输入 &code&C:\Windows\py.exe&/code&。&/li&&li&如果它没有运行,试着重新安装 Python。并且确认在安装向导中选择了 “Add Python to PATH”。参考 &a href=&https://link.zhihu.com/?target=https%3A//docs.python.org/3/using/windows.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&docs.python.org/3/using/windows.html&/a& 中的详细介绍。&/li&&li&如果仍然不能运行,那就使用 Linux 吧!它是免费的,只要将你的 Python 文件保存到一个 U 盘中,你甚至不需要安装它就可以使用。&/li&&/ul&&/ul&&p&&br&&/p&&h2&&code&Ninja-IDE&/code&&/h2&&p&&a href=&https://link.zhihu.com/?target=http%3A//ninja-ide.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Ninja-IDE&/a& 是一个优秀的 Python IDE。它有关键字高亮功能可以帮助你检测拼写错误、引号和括号补全以避免语法错误,行号(在调试时很有帮助)、缩进标记,以及运行按钮可以很容易地进行快速代码测试。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-907d05badc5a2f13daba671d_b.jpg& data-size=&normal& data-rawwidth=&729& data-rawheight=&507& class=&origin_image zh-lightbox-thumb& width=&729& data-original=&https://pic1.zhimg.com/v2-907d05badc5a2f13daba671d_r.jpg&&&figcaption&Ninja-IDE&/figcaption&&/figure&&p&&br&&/p&&p&要使用它:&/p&&ol&&li&安装 Ninja-IDE。如果你使用的是 Linux,使用包管理器安装是非常简单的;否则, 从 NINJA-IDE 的网站上 &a href=&https://link.zhihu.com/?target=http%3A//ninja-ide.org/downloads/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&下载&/a& 合适的安装版本。&/li&&li&启动 Ninja-IDE。&/li&&li&转到 Edit 菜单,并选择 Preferences 设置。&/li&&li&在 Preferences 窗口中,点击 Execution 选项卡。&/li&&li&在 Execution 选项卡上,更改 &code&python&/code& 为 &code&python3&/code&。&/li&&/ol&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-626f46264fcd7e0ba2404751ecd8e4e1_b.jpg& data-size=&normal& data-rawwidth=&729& data-rawheight=&202& class=&origin_image zh-lightbox-thumb& width=&729& data-original=&https://pic4.zhimg.com/v2-626f46264fcd7e0ba2404751ecd8e4e1_r.jpg&&&figcaption&Ninja-IDE 中的 Python3&/figcaption&&/figure&&p&&br&&/p&&h2&&b&告诉 Python 想做什么&/b&&/h2&&p&关键字可以告诉 Python 你想要做什么。不论是在 IDLE 还是在 Ninja 中,转到 File 菜单并创建一个新文件。对于 Ninja 用户:不要创建一个新项目,仅创建一个新文件。&/p&&p&在你的新的空文件中,在 IDLE 或 Ninja 中输入以下内容:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&print(&Hello world.&)
&/code&&/pre&&/div&&ul&&li&如果你使用的是 IDLE,转到 Run 菜单并选择 Run module 选项。&/li&&li&如果你使用的是 Ninja,在左侧按钮条中点击 Run File 按钮。&/li&&/ul&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-6a770eb5f39c5a01c1a81ad2d869f51c_b.jpg& data-size=&normal& data-rawwidth=&326& data-rawheight=&293& class=&content_image& width=&326&&&figcaption&在 Ninja 中运行文件&/figcaption&&/figure&&p&关键字 &code&print&/code& 告诉 Python 去打印输出在圆括号中引用的文本内容。&/p&&p&虽然,这并不是特别刺激。在其内部, Python 只能访问基本的关键字,像 &code&print&/code&、 &code&help&/code&,最基本的数学函数,等等。&/p&&p&可以使用 &code&import&/code& 关键字加载更多的关键字。在 IDLE 或 Ninja 中开始一个新文件,命名为 &code&pen.py&/code&。&/p&&p&&b&警告:&/b&不要命名你的文件名为 &code&turtle.py&/code&,因为名为 &code&turtle.py&/code& 的文件是包含在你正在控制的 turtle (海龟)程序中的。命名你的文件名为 &code&turtle.py&/code& ,将会把 Python 搞糊涂,因为它会认为你将导入你自己的文件。&/p&&p&在你的文件中输入下列的代码,然后运行它:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&import turtle
&/code&&/pre&&/div&&p&Turtle 是一个非常有趣的模块,试着

我要回帖

更多关于 比特币发行价 的文章

 

随机推荐