-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
275 lines (275 loc) · 92.9 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[可以拖拽的树形表格]]></title>
<url>%2F2019%2F08%2F18%2Fdrag-list%2F</url>
<content type="text"><![CDATA[前几天在吹逼群里见到一个问题很有意思,1234567渲染一个树状结构,节点可以拖拽,实现以下特性0.节点可以展开/收缩1.将S从上/下方拖过上一个节点T的中位线时,S节点占位移动到T节点的位置。2.将S节点拖入T节点20%-50%或50%-80%位置区间,但未穿过50%时,如果停留时间超过0.5秒,则将S节点加入T的子节点,并展开T节点。3.当用户释放正在拖拽的S节点时,调整节点从属关系。要求所有视觉由流畅的动画表现。请梳理其中数据流关系。 自己试着实现了一下 题目给了一个效果,如下 自己实现了一下,效果如下 没有过多的修改 dome 只用 css 简单做了一下移动样式的变化 比较麻烦的就是不同的移动场景要分开处理具体的代码实现: https://codepen.io/fengmumu1/pen/aboNwWd]]></content>
<categories>
<category>JavaScript</category>
</categories>
<tags>
<tag>JavaScript</tag>
<tag>拖拽</tag>
<tag>杂题</tag>
</tags>
</entry>
<entry>
<title><![CDATA[react 入参类型判断]]></title>
<url>%2F2019%2F06%2F02%2FjudgmentType%2F</url>
<content type="text"><![CDATA[在用框架的时候,我们是经常需要对传入的参数做一个类型判断的。框架一般都给我提供了对应的工具函数。比如 react 就提供了 PropTypes 这个玩意,那么如果我们要自己做判断呢,我们要如何来做一个类似的类型检测。 小试牛刀之 typeof]]></content>
<categories>
<category>JavaScript</category>
</categories>
<tags>
<tag>JavaScript</tag>
<tag>随笔</tag>
<tag>基础知识</tag>
</tags>
</entry>
<entry>
<title><![CDATA[git基本操作]]></title>
<url>%2F2019%2F04%2F08%2Fgit-note%2F</url>
<content type="text"><![CDATA[Git一直都是使用的简单的命令,比如git add、git status、git pull、git push 、git commit、git checkout 、 git merge ,这些在工作的时候基本能满足大部分的需求了,但是一些复杂点的操作,或者其中的原理还是一知半解的,所以买了一些课程,也搜集了一些资料,希望可以把git彻底搞懂, Git的基础设置 账户相关的设置 用户名称设置: git config --global user.name 'your_name 用户email设置: git config --global user.eamil '[email protected]' 我们设置的目的是,首先修改会有名字的显示,包括提以及最初的作者、其次在有变动之后可以配置利用邮箱来通知作者接收变动通知 global 处可以有一下三个参数 参数名 寓意 global 对当前用户所有仓库有效 local 只针对某一个仓库设置 system 针对所有登录的用户有效 查看账户相关的设置 用户名全局设置: git config --global --list global 处和上面的三个参数是一一对应的 创建 Git 仓库 在已有的代码的项目项目中使用 git 来管理 12cd 项目所在目录 // 如果打开位置就在目录里,就不需要进去啦git init // 然后就会给你弹相关的设置 直接用 git 新建一个项目 12cd 项目预计目录 // 如果打开位置就在目录里,就不需要进去啦git init you_project_name // 会在所在目录创建和项目名一样的文件夹,并且在里面放入 git 配置文件 git 暂存区和版本提交 我们使用 git add xx 是把文件添加到暂存区add 后面可以写多个文件名,也可以直接写 . , 来把所有的文件都添加进去。 使用 git commite 把暂存区的文件提交到版本中去。 使用 git status 我们可以查看当前项目内更改了的文件,以及文件的状态是监控了,还是未监控。使用 git 直接给文件夹重命名 使用 git mv 原始文件名 目标文件名 这个比较方便一点。 查看 git 的版本记录12345git log // 输出 git 的所有的日志// 参数-n* // 可以指定查看就近提交的数量,* 是数量,注意 * 和 n 之间没有空格。--oneline // 一个比较简洁的方式查看 log 日志--graph // 可以查看分支合并关系的一个操作 需要注意的一点是,当 log 过多且查看的时候没有指定数量,必须要使用 q (q 键)来退出。]]></content>
<categories>
<category>git</category>
</categories>
<tags>
<tag>git</tag>
<tag>技巧</tag>
<tag>笔记</tag>
</tags>
</entry>
<entry>
<title><![CDATA[动态规划之“背包问题”]]></title>
<url>%2F2018%2F08%2F11%2Fdp%2F</url>
<content type="text"><![CDATA[做个找硬币的问题,然后自己啃了一下相关的动态规划的资料,随笔如下题目要求如下1234567891011121314Coin ChangeYou are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.Example 1:Input: coins = [1, 2, 5], amount = 11Output: 3 Explanation: 11 = 5 + 5 + 1Example 2:Input: coins = [2], amount = 3Output: -1 我写的代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129/** * @param {number[]} coins * @param {number} amount * @return {number} */var coinChange1 = function(coins, amount) { let result = 0 let temp = [] //优化的结果,由于原始的递归式中,会有大量重复计算,所以把重复计算的东西存储下来。用空间换时间 for(let i = 0; i < coins.length; i++) temp.push([]) function dp(index, coin, amou){ if(amou == 0) return 0 if(index >= coin.length) return Infinity if(amou < 0) return Infinity if(temp[index][amou] !== undefined ) return temp[index][amou] //每次都有两种选择方法 //选择取当前的,取了之后(由于不是01问题所以还可以取,所以下标不变,目标减少) let a = dp(index, coin, amou - coin[index]) + 1 //不取当前的,直接取后面的,则目标不变,下标改变 let b = dp(index + 1, coin, amou) //我们看这两种哪一种取得的硬币书目少就取那种 let res = Math.min(a, b) //index 为使用哪种硬币,amoun 是目标 temp[index][amou] = res return res } result = dp(0, coins, amount) //找不到等结果为 Indinity if(result == Infinity) return -1 return result};/* 使用上面的递归式,一开始比较纠结的是那个二维数组的结构,为什么是 temp[index][amou] ,而不是 temp[amou][index] 或者其他,我们想一下人来试验拿的时候如何去拿(枚举所有结果),先从小的开始拿,比如我只拿 coins[0] 即我只用 1,那么我要11个1,然后继续我用coins[0] 和 coin[1] 两种硬币,那么我会先看 2 需要几个,然后不够的用 1 来补充,我们考虑到硬币是整数的,然后不同的硬币的组合也是整数的,所以我们是不是可以这样子想,我目标是11,我用 5 个 2 得到了 10 ,然后需要 1 个 1 ,人可以很直观的看到,机器不可以,那么我们是不是可以给一个检索信息,就是 使用 1 这种硬币拼出 1 这个目标需要多少枚硬币,我们是不是只需要看temp[index][amou]的结果就好了。然后得到了优化后的递归式,我们来试着写他的地推式*/var coinChange2 = function(coins, amount) { let temp = [] if(amount === 0) return 0 if(amount < 0) return -1 if(coins.length == 0 && amount > 0) return -1 //我们需要知道是的递推式是递归式的自下向上的写法,所以我们此时需要明确的是底到底是谁? //我们通过看上面的其实可以看到递归式的最后是index = 2,但是我们需要知道index = 2的状态是 //由边界条件生成的,所有我们需要提前手动生成一个可以推出 index = 2 的东西 for(let i = 0 ; i <= coins.length; ++i) temp.push([]) temp.forEach(item => { for(let i = 0 ; i <= amount; ++i) item.push(Infinity) }) //由于 index = 3 即没有这种硬币,所以只有为 0 不找钱的时候有结果 0 temp[coins.length][0] = 0 for(let k = coins.length - 1; k >= 0 ; k--){ for(let j = 0; j <= amount; j++){ //这个是我不用这种硬币,使用下一种硬币 temp[k][j] = temp[k + 1][j] //这个是我们此时用的硬币大于目标,只用使用下一种,所以不进入循环 //如果小于那么结果就是 取了一枚硬币 + amoun 减去此时硬币的数值后的对应值需要的硬币数 //我们之所以用循环是因为,我们使用此时的硬币后,我还可以选择这个硬币,所以我还需要重复这个步骤 //即我还可以再取这个硬币 for(let i = 1; i <= amount/coins[k] ; i++) { let pre = temp[k][j - coins[k] * i] if(pre < Infinity) temp[k][j] = Math.min(temp[k][j], pre + i) } } } if(temp[0][amount] < Infinity) return temp[0][amount] return -1}/*上面的时间复杂度很高,所以需要简化一下*/var coinChange3 = function(coins, amount) { let temp = [] if(amount === 0) return 0 if(amount < 0) return -1 if(coins.length == 0 && amount > 0) return -1 for(let i = 0 ; i <= coins.length; ++i) temp.push([]) temp.forEach(item => { for(let i = 0 ; i <= amount; ++i) item.push(Infinity) }) temp[coins.length][0] = 0 for(let k = coins.length - 1; k >= 0 ; k--){ for(let j = 0; j <= amount; j++){ if( j - coins[k] > 0){ //我们去掉了这个循环,是因为我们想一下,取了当前的硬币,然后最小的硬币数目,就是使用当前硬币数的 //amoun - 硬币面额 后的目标 需要最小硬币数 + 1 (我们此时取的硬币) let a = temp[k + 1][j] let b = temp[k][j - coins[k]] temp[k][j] = Math.min(a, b + 1) } else { temp[k][j] = temp[k + 1][j] } } } if(temp[0][amount] < Infinity) return temp[0][amount] return -1}/*时间复杂度降低了,我们试着降低一下空间复杂度*/var coinChange4 = function(coins, amount) { let temp = [] if(amount === 0) return 0 if(amount < 0) return -1 if(coins.length == 0 && amount > 0) return -1 for(let i = 0 ; i <= amount; ++i) temp.push(Infinity) temp[0] = 0 for(let k = coins.length - 1; k >= 0 ; k--){ for(let j = 0; j <= amount; j++){ if(j - coins[k] > 0){ let a = temp[j] let b = temp[j - coins[k]] temp[j] = Math.min(a, b + 1) } else { temp[j] = temp[j] } } } if(temp[amount] < Infinity) return temp[amount] return -1}/*这个文字不好描述,一般动态规划都可以使用滚动数组来存放,然后我们发现这个东西用到的都是数组的一半空间所以使用一个一维数组,需要自己画一下图就可以理解了*/ console.log(coinChange([1,2,5],11)) 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899/*我们如果硬币不能重复呢?,我们如何做*/var coinChangeTwo1 = function(coins, amount) { let result = 0 function dp(index, coin, amou){ if(amou === 0) return 0 if(amou < 0) return Infinity if(index > coin.length) return Infinity //不管用不用,我们都要给下标加 1 let a = dp(index + 1, coin, amou - coin[index]) + 1 let b = dp(index + 1, coin, amou) return Math.min(a, b) } result = dp(0, coins, amount) if(result !== Infinity) return result return -1 }/*我们试着自底向上写出递推式*/var coinChangeTwo2 = function(coins, amount) { let result = 0 let temp = [] if(amount === 0) return 0 if(amount < 0) return -1 if(coins.length == 0 && amount > 0) return -1 for(let i = 0 ; i <= coins.length; ++i) temp.push([]) temp.forEach(item => { for(let i = 0 ; i <= amount; ++i) item.push(Infinity) }) temp[coins.length][0] = 0 for(let i = coins.length - 1; i >= 0; i--){ for(let j = 0; j <= amount; ++j){ //我们需要考虑如果我取了这个硬币,这个硬币不应该大于目标数额 if(j - coins[i] >= 0) { let a = temp[i + 1][j] let b = temp[i + 1][j - coins[i]] + 1 temp[i][j] = Math.min(a, b) } else { //如果硬币大于目标数额,无法取当前的硬币 temp[i][j] = temp[i + 1][j] } } } result = temp[0][amount] if(result !== Infinity) return result return -1 }/*我们是可以利用滚动数组再优化的,然后如果我们需要知道我使用了那些硬币呢?我该如何操作我想到的是保留这些数据然后反向查询*/var coinChangeTwo3 = function(coins, amount) { let result = 0 let temp = [] if(amount === 0) return 0 if(amount < 0) return -1 if(coins.length == 0 && amount > 0) return -1 for(let i = 0 ; i <= coins.length; ++i) temp.push([]) temp.forEach(item => { for(let i = 0 ; i <= amount; ++i) item.push(Infinity) }) let fonit = [] temp[coins.length][0] = 0 for(let i = coins.length - 1; i >= 0; i--){ for(let j = 0; j <= amount; ++j){ temp[i][j] = temp[i + 1][j] if(j - coins[i] >= 0) { let a = temp[i + 1][j] let b = temp[i + 1][j - coins[i]] + 1 temp[i][j] = Math.min(a, b) } } } let w = temp[0][amount] let s = 0 let am = amount //我们看我们用了几个硬币,且我们可以拼出目标结果 while(w > 0 && w !== Infinity) { //如果一个数据的下一行不是无穷大,那么说明我没有取这一行的硬币 if(temp[s + 1][am] !== Infinity) s = s + 1 //如果是无穷大,我必须要取这一行的硬币, if(temp[s + 1][am] == Infinity) { fonit.push(s) am = am - coins[s] s = s + 1 w-- } } console.log(fonit) result = temp[0][amount] if(result !== Infinity) return result return -1 } 我没有写没有可以重复取硬币的记录,不过大同小异]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>算法</tag>
<tag>动态规划</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Multiply-Strings]]></title>
<url>%2F2018%2F08%2F05%2FMultiply-Strings%2F</url>
<content type="text"><![CDATA[题目:Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string. 1234567891011121314151617181920212223242526272829303132333435/** * @param {string} num1 * @param {string} num2 * @return {string} */var multiply = function(num1, num2) { debugger let numa = num1.split("") let numb = num2.split("") let result = [] let re = [] if(numa.length === 0 || numb.length === 0) return '0' if((numa.length === 1 && numa[0] === '0' )|| (numb.length === 1 && numb[0] === '0')) return '0' result.length = (numa.length + numb.length) result.fill(0) for(let i = numa.length - 1; i >= 0; i--) { for(let j = numb.length -1; j >= 0; j--) { let sum = numa[i] * numb[j] let p1 = i + j let p2 = i + j + 1 sum += result[p2] result[p1] += sum / 10 >> 0 result[p2] = sum % 10 } } let k = 0 while(result[k] === 0) k++ for(let i = k; i < result.length; i++) { re.push(result[i]) } return re.join("")}; 题目连接参考资料]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>大数相加</tag>
</tags>
</entry>
<entry>
<title><![CDATA[双指针]]></title>
<url>%2F2018%2F07%2F13%2Ftwo-pointers%2F</url>
<content type="text"><![CDATA[今天做了一个题目:Remove Element12345678Given an array nums and a value val, remove all instances of that value in-place and return the new length.Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.The order of elements can be changed. It doesn't matter what you leave beyond the new length.Example 1:Given nums = [3,2,2,3], val = 3,Your function should return length = 2, with the first two elements of nums being 2.It doesn't matter what you leave beyond the returned length. 大概就是把数组中与val一致的数值去掉,然后,返回与val一致的元素的个数,题目不允许额外再使用一个数组。我上传一下我写的代码123456789101112131415var removeElement = function(nums, val) { let leave = 0 let wipe = 0 let flag = 0 for( ; wipe < nums.length; wipe++){ if(nums[wipe] === val){ for(leave = wipe; leave < nums.length; leave++){ nums[leave] = nums[leave + 1] } wipe-- flag++ } } return nums.length - flag}; 上传之后我看了一下排在我前面人的代码12345678910111213141516var removeElement = function(nums, val) { var first = 0 var last = nums.length - 1 while (first < last) { if (nums[first] == val) { nums[first] = nums[last] last-- } else{ first++ } } if (nums[first] != val) { first++ } return first}; 双指针他的写法时间复杂度是O(n),而我的是O(n^2),因为他用了双指针法(two-pointers),双指针(这里的指针不同于c语言的指针,这里说的是数组的下标),指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向或者相反方向的指针进行扫描,从而达到相应的目的。由于数组有一定的顺序,使用这种方法往往可以简化运算。 双指针的使用场景求元素和eag:给一个有序数组和一个数值,查找数组中是否有任意两个元素的合为指定的数值,有的话返回元素的下标(有多对数值只返回一对)。解决的思路是,给两个游标一个指向数组首(star),一个指向数组尾(end)。判断两个元素合(x)与数值(y)之间的关系,我们假定数组是从小到大排序的,如果 x > y 我们就给 end + 1 ,如果x < y 我们就给 star + 1。 hoare的双向扫描快速划分法()算法原理:使用left和right将数组划分成三部分,left之前的部分为小于等于划分元素P的值,right之后的部分为大于划分元素P的值,left和right之间的部分是没有进行划分的区域。外循环使得left自左向右遍历,同时right自右向左遍历,在这个过程中当left遇见大于P的值则停止,等待right遇见小于等于P的值又停止之后,交换他们的值,这个循环在left和right相遇或者交叉之后停止。最后交换a[r]和left的值,并返回left;参考链接 求链表中间元素对于单链表求中间元素的问题,经典的作法是采用两个指针,初始化都指向链表表头,移动开始时,快指针移动两步,慢指针移动一步。当快指针的next为null或者快指针为null的时候,慢指针所指的就是单链表的中间元素(注意奇数个元素和偶数个元素的处理) 当然这个不是全部啦,以后发现的话再慢慢补上。]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>leetcode</tag>
<tag>two-pointers</tag>
</tags>
</entry>
<entry>
<title><![CDATA[hexo上传报错:No such device or address]]></title>
<url>%2F2018%2F07%2F12%2Fno-address%2F</url>
<content type="text"><![CDATA[今天使用hexo上传,报错(bash: /dev/tty: No such device or address)个人推测和网络有关(网太慢了),但是不想等,所以就搜了一下解决方法就是在站点配置的上传设置,把地址改一下:1234567891011deploy: type: git repo: https://github.com/你GitHub注册用户名/你GitHub注册用户名.github.io.git branch: master 改为:deploy: type: git repo: [email protected]:你GitHub注册用户名/你GitHub注册用户名.github.io.git branch: master 个人推测,由于网络不好,所以触发github的安全机制,所以提交失败,改设置之后,由原来的https提交变成了使用ssh来提交,就比较好通过了。 解决方法原文]]></content>
<categories>
<category>hexo</category>
</categories>
<tags>
<tag>hexo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[数字转成字母]]></title>
<url>%2F2018%2F07%2F12%2FInteger-to-English-Words%2F</url>
<content type="text"><![CDATA[发现一个有小坑的题目 Integer to English Words题目要求:1234567891011121314151617Convert a non-negative integer to its english words representation. Given input is guaranteed to be less than 231 - 1.Example 1:Input: 123Output: "One Hundred Twenty Three"Example 2:Input: 12345Output: "Twelve Thousand Three Hundred Forty Five"Example 3:Input: 1234567Output: "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven"Example 4:Input: 1234567891Output: "One Billion Two Hundred Thirty Four Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety One" 就是把一串数字按照英语语法格式输出成字符串的形式。英语不同于汉语,是3个一断。汉语和英语数字表达的方式不同。汉语是个,十,百,千,万,十万,百万,千万,亿,十亿……,也就是以“十”的倍数来表示;而英语则是在数字超过千以后,以“千”(thousand)的倍数来表达的。如“一万”是“十千”,即 ten thousand;“十万”是“百千”,即 hundred thousand,直至“百万”,million。百万以上的数字则用“百万”的倍数表达;如“千万”是“十百万”,即 ten million;“亿”是“百百万”,即 hundred million,直至“十亿”,billion。 所以英文表达数字时可以从右往左,三位一逗号,逗号从右往左分别对应的是:thousand, million, billion, etc。 @沪江英语www.hjenglish.com/new/p110563所以程序并不难想,思路也没有那么难,写完之后,一提交发现坑了,丫的最后面不能有空格,改了半天,最后实现了功能,发现代码很长,最后用了自带的函数trim,来去掉了多余的空格,代码也就将就算是自己能看过眼吧。下面是丑代码12345678910111213141516171819202122232425262728293031323334353637383940414243/** * @param {number} num * @return {string} */var numberToWords = function(num) { //debugger if(num === 0) return 'Zero' let cous = "" let index = 0 let a = [""," One", " Two", " Three", " Four", " Five", " Six", " Seven", " Eight"," Nine", " Ten", " Eleven", " Twelve", " Thirteen", " Fourteen", " Fifteen", " Sixteen", " Seventeen", " Eighteen", " Nineteen"] let b = ["",""," Twenty", " Thirty", " Forty", " Fifty", " Sixty", " Seventy", " Eighty", " Ninety"] let c = [""," Thousand", " Million", " Billion"] let thereword = function (numb) { if (numb === 0) return "" let num_temp = "" // debugger if(numb > 99){ if(numb % 100 > 19) { num_temp = a[parseInt(numb / 100)] + " Hundred" + b[parseInt((numb % 100) / 10)] + a[parseInt((numb % 100) % 10)] } else { num_temp = a[parseInt(numb / 100)] + " Hundred" + a[numb % 100] } } else { if(numb > 19) { num_temp = b[parseInt(numb / 10)] + a[numb % 10] } else { num_temp = a[numb] } } return num_temp } while(num > 0) { let nums = thereword(num % 1000) if(nums !== "") { cous = nums + c[index] + cous } else { cous = nums + cous } num = (num - num % 1000) / 1000 index++ } return cous.trim()}; 以后需要注意更多的细节要求]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>leetcode</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Eloquent_JavaScrip中的weresquirrel]]></title>
<url>%2F2018%2F07%2F12%2FEloquent-JavaScript-of-weresquirrel%2F</url>
<content type="text"><![CDATA[看到了Eloquent_JavaScrip第四章(对象和数组)),这一章讲了一个松鼠人(weresquirrel)的故事,并用函数来找出其变身的原因,感觉很有趣,便动手实现了一下。数据连接123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189var JOURNAL = [ {"events":["carrot","exercise","weekend"],"squirrel":false}, {"events":["bread","pudding","brushed teeth","weekend","touched tree"],"squirrel":false}, {"events":["carrot","nachos","brushed teeth","cycling","weekend"],"squirrel":false}, {"events":["brussel sprouts","ice cream","brushed teeth","computer","weekend"],"squirrel":false}, {"events":["potatoes","candy","brushed teeth","exercise","weekend","dentist"],"squirrel":false}, {"events":["brussel sprouts","pudding","brushed teeth","running","weekend"],"squirrel":false}, {"events":["pizza","brushed teeth","computer","work","touched tree"],"squirrel":false}, {"events":["bread","beer","brushed teeth","cycling","work"],"squirrel":false}, {"events":["cauliflower","brushed teeth","work"],"squirrel":false}, {"events":["pizza","brushed teeth","cycling","work"],"squirrel":false}, {"events":["lasagna","nachos","brushed teeth","work"],"squirrel":false}, {"events":["brushed teeth","weekend","touched tree"],"squirrel":false}, {"events":["lettuce","brushed teeth","television","weekend"],"squirrel":false}, {"events":["spaghetti","brushed teeth","work"],"squirrel":false}, {"events":["brushed teeth","computer","work"],"squirrel":false}, {"events":["lettuce","nachos","brushed teeth","work"],"squirrel":false}, {"events":["carrot","brushed teeth","running","work"],"squirrel":false}, {"events":["brushed teeth","work"],"squirrel":false}, {"events":["cauliflower","reading","weekend"],"squirrel":false}, {"events":["bread","brushed teeth","weekend"],"squirrel":false}, {"events":["lasagna","brushed teeth","exercise","work"],"squirrel":false}, {"events":["spaghetti","brushed teeth","reading","work"],"squirrel":false}, {"events":["carrot","ice cream","brushed teeth","television","work"],"squirrel":false}, {"events":["spaghetti","nachos","work"],"squirrel":false}, {"events":["cauliflower","ice cream","brushed teeth","cycling","work"],"squirrel":false}, {"events":["spaghetti","peanuts","computer","weekend"],"squirrel":true}, {"events":["potatoes","ice cream","brushed teeth","computer","weekend"],"squirrel":false}, {"events":["potatoes","ice cream","brushed teeth","work"],"squirrel":false}, {"events":["peanuts","brushed teeth","running","work"],"squirrel":false}, {"events":["potatoes","exercise","work"],"squirrel":false}, {"events":["pizza","ice cream","computer","work"],"squirrel":false}, {"events":["lasagna","ice cream","work"],"squirrel":false}, {"events":["cauliflower","candy","reading","weekend"],"squirrel":false}, {"events":["lasagna","nachos","brushed teeth","running","weekend"],"squirrel":false}, {"events":["potatoes","brushed teeth","work"],"squirrel":false}, {"events":["carrot","work"],"squirrel":false}, {"events":["pizza","beer","work","dentist"],"squirrel":false}, {"events":["lasagna","pudding","cycling","work"],"squirrel":false}, {"events":["spaghetti","brushed teeth","reading","work"],"squirrel":false}, {"events":["spaghetti","pudding","television","weekend"],"squirrel":false}, {"events":["bread","brushed teeth","exercise","weekend"],"squirrel":false}, {"events":["lasagna","peanuts","work"],"squirrel":true}, {"events":["pizza","work"],"squirrel":false}, {"events":["potatoes","exercise","work"],"squirrel":false}, {"events":["brushed teeth","exercise","work"],"squirrel":false}, {"events":["spaghetti","brushed teeth","television","work"],"squirrel":false}, {"events":["pizza","cycling","weekend"],"squirrel":false}, {"events":["carrot","brushed teeth","weekend"],"squirrel":false}, {"events":["carrot","beer","brushed teeth","work"],"squirrel":false}, {"events":["pizza","peanuts","candy","work"],"squirrel":true}, {"events":["carrot","peanuts","brushed teeth","reading","work"],"squirrel":false}, {"events":["potatoes","peanuts","brushed teeth","work"],"squirrel":false}, {"events":["carrot","nachos","brushed teeth","exercise","work"],"squirrel":false}, {"events":["pizza","peanuts","brushed teeth","television","weekend"],"squirrel":false}, {"events":["lasagna","brushed teeth","cycling","weekend"],"squirrel":false}, {"events":["cauliflower","peanuts","brushed teeth","computer","work","touched tree"],"squirrel":false}, {"events":["lettuce","brushed teeth","television","work"],"squirrel":false}, {"events":["potatoes","brushed teeth","computer","work"],"squirrel":false}, {"events":["bread","candy","work"],"squirrel":false}, {"events":["potatoes","nachos","work"],"squirrel":false}, {"events":["carrot","pudding","brushed teeth","weekend"],"squirrel":false}, {"events":["carrot","brushed teeth","exercise","weekend","touched tree"],"squirrel":false}, {"events":["brussel sprouts","running","work"],"squirrel":false}, {"events":["brushed teeth","work"],"squirrel":false}, {"events":["lettuce","brushed teeth","running","work"],"squirrel":false}, {"events":["candy","brushed teeth","work"],"squirrel":false}, {"events":["brussel sprouts","brushed teeth","computer","work"],"squirrel":false}, {"events":["bread","brushed teeth","weekend"],"squirrel":false}, {"events":["cauliflower","brushed teeth","weekend"],"squirrel":false}, {"events":["spaghetti","candy","television","work","touched tree"],"squirrel":false}, {"events":["carrot","pudding","brushed teeth","work"],"squirrel":false}, {"events":["lettuce","brushed teeth","work"],"squirrel":false}, {"events":["carrot","ice cream","brushed teeth","cycling","work"],"squirrel":false}, {"events":["pizza","brushed teeth","work"],"squirrel":false}, {"events":["spaghetti","peanuts","exercise","weekend"],"squirrel":true}, {"events":["bread","beer","computer","weekend","touched tree"],"squirrel":false}, {"events":["brushed teeth","running","work"],"squirrel":false}, {"events":["lettuce","peanuts","brushed teeth","work","touched tree"],"squirrel":false}, {"events":["lasagna","brushed teeth","television","work"],"squirrel":false}, {"events":["cauliflower","brushed teeth","running","work"],"squirrel":false}, {"events":["carrot","brushed teeth","running","work"],"squirrel":false}, {"events":["carrot","reading","weekend"],"squirrel":false}, {"events":["carrot","peanuts","reading","weekend"],"squirrel":true}, {"events":["potatoes","brushed teeth","running","work"],"squirrel":false}, {"events":["lasagna","ice cream","work","touched tree"],"squirrel":false}, {"events":["cauliflower","peanuts","brushed teeth","cycling","work"],"squirrel":false}, {"events":["pizza","brushed teeth","running","work"],"squirrel":false}, {"events":["lettuce","brushed teeth","work"],"squirrel":false}, {"events":["bread","brushed teeth","television","weekend"],"squirrel":false}, {"events":["cauliflower","peanuts","brushed teeth","weekend"],"squirrel":false}];/** * 判断是否有事件 * @param {String}event 事件名称 * @param {Object}entry 事件记录 * @return {Boolean} true是有 false是没有 */var isEvent = function(event, entry) { //indexOf查找不到就返回-1,注意,在Bolean中false为0,所有非0 的都是true return entry.indexOf(event) !== -1}/** * 计算两件事件的相关性 * @param {Number[]} record_tab ab 发生与否记作0和1,然后统计所有的情况记成数组 * @return {string}} 二者的相关性[-1,1],使用了内置函数保留10为有效数字所以转化成了字符串 */var phi = function(record_tab) { let temp = Math.sqrt( (record_tab[2] + record_tab[3]) * (record_tab[1] + record_tab[3]) * (record_tab[0] + record_tab[1]) * (record_tab[0] + record_tab[2]) ) return ((record_tab[3] * record_tab[0] - record_tab[2] * record_tab[1]) / temp).toFixed(10) }/** * 统计事件与是否变身的相关性 * @param {String} event 事件名称 * @param {Object} tab 事件记录 * @return {Number} 事件与变身的相关性[-1,1] */var sth_pertinence = function(event, tab) { let phi_tab = [0,0,0,0] for(var i = 0; i < tab.length; i++) { let index = 0 if(isEvent(event,tab[i].events)) {index++} if(tab[i].squirrel) {index += 2} phi_tab[index]++ } return phi(phi_tab)}/** * 相关性映射表 * @param {Object} tabs 记录表 * @return {object} 相关性映射表 */var map_pertinence = function(tabs) { let map = {} for(let i = 0; i < tabs.length; i++) { for(let j = 0; j < tabs[i].events.length; j++){ if( ! (tabs[i].events[j] in map)) { map[tabs[i].events[j]] = Number(sth_pertinence(tabs[i].events[j] ,JOURNAL)) } } } return map}/** * 找出相关项 * @param {object} map 相关性映射表 * @return {string} 分析结果 */var reous_pertinence = function(map) { let tab_phi = {} let reous = { max_tab : "", max_phi : -Infinity , min_tab : "", min_phi : Infinity, } let end_resou = "" tab_phi = map_pertinence(JOURNAL) for(let event in tab_phi) { if(tab_phi[event] < reous.min_phi ) { reous.min_tab = event reous.min_phi = tab_phi[event] } if(tab_phi[event] > reous.max_phi) { reous.max_tab = event reous.max_phi = tab_phi[event] } } end_resou = reous.max_tab + " no" + reous.min_tab for(let i = 0; i < JOURNAL.length ; i++){ if(isEvent(reous.max_tab,JOURNAL[i].events) && !isEvent(reous.min_tab,JOURNAL[i].events) ){ JOURNAL[i].events.push(end_resou) } } return end_resou +" pshi: "+ sth_pertinence(end_resou,JOURNAL)}console.log(reous_pertinence())]]></content>
<categories>
<category>JavaScript</category>
</categories>
<tags>
<tag>JavaScript</tag>
<tag>杂谈</tag>
</tags>
</entry>
<entry>
<title><![CDATA[丑数2之自己挖坑埋自己]]></title>
<url>%2F2018%2F07%2F09%2FUgly-Number-II%2F</url>
<content type="text"><![CDATA[今天做了丑数2,遇到个坑,卡主自己好久,所以make先,以后有空再仔细研究先上题目:12345678910111213Write a program to find the n-th ugly number.Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. Example:Input: n = 10Output: 12Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.Note: 1 is typically treated as an ugly number. n does not exceed 1690. 先给出我最终通过的代码:123456789101112131415161718192021222324252627282930313233343536373839404142434445var nthUglyNumber = function(n) { //debugger var arry = [] var arry_two = [2] var i = 0 var arry_three = [3] var j = 0 var arry_five = [5] var k = 0 var a = arry_two[i] var b = arry_three[i] var c = arry_five[i] if (n < 5) { return n } while (1) { if ( a < b && a < c) { arry_two.push(a * 2) arry_three.push(a * 3) arry_five.push(a * 5) arry.push(a) a = arry_two[i += 1] } else if(b < a && b < c ) { arry_three.push(b * 3) arry_five.push(b * 5) arry.push(b) b = arry_three[j += 1] } else if (c < a && c < b) { arry_five.push(c * 5) arry.push(c) c = arry_five[k += 1] } if(arry.length + 1 === n) break } //console.log(arry) return arry[n - 2] //减去 0和 1};//console.log(nthUglyNumber(5)) 现在来分析一下解决这个题目的思路:1234567891011121314151617181920212223242526丑数就是只由2 3 5 乘出来的数字,我们定义三个数组,我们每次三个数组最小的数字,在第一组就分别乘以 2 3 5 放入 三个数组 arry_two 2 arry_three 3 arry_five 5arry_two 2 4arry_three 3 6arry_five 5 10然后我们把最小的取出来arry_two x 4arry_three 3 6arry_five 5 10此时最小的是3,他位于第二个数组,我们给他 乘以3和5分别放入第二个和第三个数组arry_two x 4 arry_three 3 6 9arry_five 5 10 15我们去出3,此时最小的是4,4 位于第一个数组,我们乘以2 3 5 后分别放入三个数组arry_two x 4 8 arry_three x 6 9 12arry_five 5 10 15 20我们拿去4 后最小的是5,然后我们 给5 乘以5放入第三个数组arry_two x x 8 arry_three x 6 9 12arry_five 5 10 15 20 25然后我们把每次拿出来的数字,放到一个数组,就是从2开始的丑数啦 在再放出我一开始的问题程序:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364var nthUglyNumber = function(n) { //debugger var ff = n n = n + 150 var count = 4 //1也是丑数 var arry = [] var arry_temp = [] var arry_two = [2] var i = 0 var arry_three = [3] var j = 0 var arry_five = [5] var k = 0 var a = arry_two[i] var b = arry_three[i] var c = arry_five[i] if (ff < 5) { return ff } while (1) { if ( a < b && a < c) { arry_two.push(a * 2) count++ if(count === n) break arry_three.push(a * 3) count++ if(count === n) break arry_five.push(a * 5) count++ if(count === n) break a = arry_two[i += 1] } else if(b < a && b < c ) { arry_three.push(b * 3) count++ if(count === n) break arry_five.push(b * 5) count++ if(count === n) break b = arry_three[j += 1] } else if (c < a && c < b) { arry_five.push(c * 5) count++ if(count === n) break c = arry_five[k += 1] } } arry_temp = arry_two.concat(arry_three) arry = arry_temp.concat(arry_five) function sortNumber(a,b){ return a - b } arry.sort(sortNumber) //console.log(arry) return arry[n - 152] //多算了x个 减去 0和 1}; 这个程序的思路没有放在取出来的丑数上,而是放在了求出来的丑数上,我计算出目前算了多少个丑数,比如要10个我就计算10个,结果发现求出来的并没有按顺序(中间有空缺),比如算10个丑数,其实只计算到了15,计算第11个丑数的时候才把12计算出来,当时头脑一发热,好不是少计算了,那我多计算好了,所以我们多计算150个,结果在1 和 1690 的时候都对,在(1406,1430)之间不对,其余数字都对,真让人心累,为什么出现这样情况,现在头脑不清楚,有空好好进去瞅瞅,应该还是少计算的原因,不过比他大的数字都是好的,这个就很奇怪了,不过就算这个可以通过测试,比如我多计算500个或者600个。这个思路都是有问题的,不是好思路。]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>算法</tag>
<tag>leetcode</tag>
</tags>
</entry>
<entry>
<title><![CDATA[line_text]]></title>
<url>%2F2018%2F07%2F08%2Fline-text%2F</url>
<content type="text"></content>
</entry>
<entry>
<title><![CDATA[牛顿-拉弗森方法(Newton-Raphson_method)求平方根]]></title>
<url>%2F2018%2F07%2F08%2FNewton-Raphson-method%2F</url>
<content type="text"><![CDATA[牛顿法(英语:Newton’s method)又称为牛顿-拉弗森方法(英语:Newton-Raphson method),它是一种在实数域和复数域上近似求解方程的方法。方法使用函数 {\displaystyle f(x)} f(x)的泰勒级数的前面几项来寻找方程 {\displaystyle f(y)=0} {\displaystyle f(y)=0}的根。 维基解密 @https://zh.wikipedia.org/wiki/%E7%89%9B%E9%A1%BF%E6%B3%95 再leetcode上看到这么一道题,题目很简单:1234Sqrt(x)Implement int sqrt(int x).Compute and return the square root of x, where x is guaranteed to be a non-negative integer.Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned. 就是求一个数字的平方根,嗯题目没有截取完整们对于开方开出来是小数的,直接抛弃小数位(不是四舍五入)。解题思路可以有很多,比较快的就是牛顿法了,一开始没有一下子想通牛顿法咋做,后来想通啦,所以就记录一下。首先我们列一个关于被开方数z(在程序中是入口参数x)以及开放根x1的方程,x1 * x1 - z = y,我们把它记成F(x),当 y === 0 的时候说明x1为z的开放根。我们把他的图像画出来,图像如下(图是我从维基百科上偷得,自己的灵魂画图太丑了) 我们在x轴上找一点x0,过xo在F(x)的位置上做一条切线L1,我们可以看到L1与x轴的交点x1是逐渐逼近与F(x)与x轴的交点的,而这个交点也就是我们要求的开放根,然后我们继续做过x1在F(x)上的切线我们得到x2,不断的迭代下去,我们就可以得到一个符合我们要求的精确范围内的开放根。现在我们需要用函数来写出来,我们想到了递归,但是想一下递归的空间复杂度,所以我们用循环来做,我们只需要不断的求x直到x满足要求的精度我们就跳出循环。让我们来想一下我们如何通过现在的x来的出下一个x1呢?我们看图像L1是F(x)在x0处的切线,那么这条切线的斜率就是F(x)的导函数在x0的结果。 现在我们这样子看一下123456789101112原函数F(x): x1 *x1 - z 原函数的导函数f'(x): 2 * x1过x0的切线的方程我们设为:y = k*x + b 现在带入x0在此处的斜率和y k = 2 * x0 y = x0 * x0 - z我们得b = x0 * x0 - z - 2 * x0 * x0所以得到x0的方程是 : y = 2 * x0 * x + x0 * x0 - z - 2 * x0 * x0 = 2 * x0 * x - z - x0 * x0我们可以看到,L1与x轴相交的点就是我们要求的x1,此时y = 0,所以x1 = (x0 * x0 + z)/ (2 * x0 * 10) 然后的出的x1不满足精确度,我们就把x1带入上面的式子,得出x2,然后不断迭代。代码如下12345678var mySqrt = function(x) { var cout = 2 while (Math.abs(cout ** 2 - x) > 0.0000001) { cout = (cout ** 2 + x) / (2 * cout) } return parseInt(cout)};]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>算法</tag>
<tag>leetcode</tag>
</tags>
</entry>
<entry>
<title><![CDATA[leetcode之Counting_Bits]]></title>
<url>%2F2018%2F07%2F07%2FCounting-Bits%2F</url>
<content type="text"><![CDATA[Counting_BitsGiven a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1’s in their binary representation and return them as an array. Example:For num = 5 you should return [0,1,1,2,1,2]. Follow up: It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass? Space complexity should be O(n). Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.Credits:Special thanks to @ syedee for adding this problem and creating all test cases.题目如上,就是给你一个数字,让给输出从0到这个数字之间所有数字转化为二进制后1的个数。12345678910111213141516171819202122// 0 0000 0 // 1 0001 1 // 2 0010 1// 3 0011 2// 4 0100 1// 5 0101 2// 6 0110 2// 7 0111 3// ------------- // 8 1000 1 // 9 1001 2 // 10 1010 2 // 11 1011 3 // 12 1100 2 // 13 1101 3// 14 1110 3// 15 1111 4// 16 10000 1// 17 10001 2// 31 1 1111 5// 63 11 1111 6 解法一:12345678var countBits = function(num) { debugger var res = [0] for (var i = 1; i <= num; ++i) { if (i % 2 == 0) res.push(res[parseInt(i / 2)]) else res.push(res[parseInt((i / 2))] + 1) } return res解题思路:从1开始,遇到偶数时,其1的个数和该偶数除以2得到的数字的1的个数相同, 遇到奇数时,其1的个数等于该奇数除以2得到的数字的1的个数然后再加上1第二种思路:1234567var countBits = function(num) { debugger var res = [0] for (int i = 1; i <= num; ++i) { res[i] = res[i & (i - 1)] + 1; } return res解题思路:每个i值都是i&(i-1)对应的值加1 (简单暴力,神奇的n与n-1) 第二种参考自Grandyangde的博客:]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>算法</tag>
<tag>leetcode</tag>
</tags>
</entry>
<entry>
<title><![CDATA[使用ftp方式上传博客]]></title>
<url>%2F2018%2F07%2F07%2Fhexo-ftp%2F</url>
<content type="text"><![CDATA[在github上传博客,有时候会失败,而且速度也很慢,所以就想放到国内的服务器上,怎奈何囊中羞涩买不起服务器,手里正好有个云主机,所以就用ftp的形式上传hexo的静态文件啦先放上hexo的官方文档的传送门点我先在你的bloge目录运行如下代码:1$ npm install hexo-deployer-ftpsync --save 然后在站点配置文件找到deploy:我的配置是这样子的:123456789101112131415deploy:- type: git repo: xxxxxxxx branch: master- type: ftpsync host: xxxxx #主机地址 user: xxxx #用户名 pass: xxxx #密码 //注意我用的是阿里云的云主机,按照他的规定我必须把文件放到根目录下的htdocs文件夹内 remote: /htdocs/ #上传到空间的指定目录。比如/public_html/。默认为/ port: 21 #端口,默认为21 //logreport 也是云主机的文件,无法删除,需要忽略它,都则会报错 ignore: [/logreport] #忽略的文件 connections: 1 #使用的连接数,默认1 verbose: true #显示调试信息,默认false hexo本身支持多站点上传,所以我们不需要删除以前的上传方式,不过注意正确的缩进以及空格 由于使用ftpsync上传,每次都会删除以前的文件,所以把你没有权限删除的以及不想删除或者修改的文件写到ignore这里,ignore: [“/s”,”/c”],中间要用逗号隔开,注意路径(引号貌似可以不加)]]></content>
<categories>
<category>hexo</category>
</categories>
<tags>
<tag>ftp</tag>
<tag>hexo上传</tag>
</tags>
</entry>
<entry>
<title><![CDATA[浅谈立即执行函数]]></title>
<url>%2F2018%2F07%2F06%2Fimmediate-execution-function%2F</url>
<content type="text"><),在这条语句执行后c指向函数d,而d在全局是undefined 因为,其只在函数内部可见,在外部不可见var c = function d() { console.log("c函数声明")} 要区分一个代码是函数声明还是函数表达式,那要看代码的应用上下文。 如果有运算符号,那它就是函数表达式。 如果没有运算符号而且不在条件判断语句中,就说明是函数声明,无法直接加()进行调用(运算符包括赋值号跟括号) 如果在条件语句中,函数声明也会强行被当做函数表达式执行。 @Kelichaogithub.com/Kelichao/javascript.basics/issues/19 注意我们如果需要向下面这样声明函数,会在不同浏览器下得到不同结果undefined 我们应该是用函数表达式声明,就可以的得到对的结果 立即执行函数(Immediately Invoked Function Expression)在我们使用函数表达式来声明函数的时候,b指向的就是函数,我们要执行函数的时候就是b()。那么b的内容是什么 ?12345678910111213141516171819我们把b的内容打印出来b == function() { console.log("b函数声明") }我们是不是想到了,如果 function() { console.log("b函数声明") }() 是不是也可以让函数得到执行,我们把这种执行叫做立即执行函数,不过此处有个坑。他会报错`token(`,因为function是个关键字,编译器在编译的时候,如果以function开头那么就应该以}结尾,但是咱么以)结尾了,所以我们只需要不让function开头就好啦,我们可以给function前面放!/+/-或者用一个()把function() { console.log("b函数声明") }() 整个包起来,或者只包裹函数声明的那一部分,不过用!/+ /-有可能改变函数的返回值,同时为了更符合函数的定义所以我们一般用()把函数声明的那一部分包起来,就变成了{% codeblock lang:Javascript %}(function f(){ console.log("xxx")})(){% endcodeblock %} 我们需要注意的是,小括号有多种语义,此时的语义是:强制表达式运算 ,被称作:分组操作符他只能包含表达式,所以此时的小括号就把语句转成了函数表达式的声明方式,但是,我们如果把return,var等语句写进去就会报语法错误 有关立即执行函数以及闭包等,等以后知识库充足了再写IIFE(Immediately Invoked Function Expression),立即执行函数表达式javascript中没用私有作用域的概念,如果在多人开发的项目上,你在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉, 根据javascript函数作用域链的特性,可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量, 而外部环境不能访问“容器”内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。]]></content>
<categories>
<category>JavaScript</category>
</categories>
<tags>
<tag>js</tag>
<tag>函数</tag>
</tags>
</entry>
<entry>
<title><![CDATA[计算素数个数的三段进阶]]></title>
<url>%2F2018%2F07%2F04%2Fcount-primes-think%2F</url>
<content type="text"><![CDATA[今天坐leetcode上的Count Primes这道题,题目要求比较的简单:Count the number of prime numbers less than a non-negative number, n. 就是给一个数字,然后输出从0到这个数字内有多少个素数。老办法先实现后优化,实现之后发现优化真不容易,借助外界各种资源后,差不多算是达到了自己想达到的效果,故记录一下此次一波三折的优化。 低阶版1234567891011121314151617function isPrimes(num) { for(var j = 2; j <= Math.sqrt(num); j++) { if(num % j == 0){ return false } } return true}var countPrimes = function(n) { var coun = 0 for(var i =2; i < n; i++) { if(isPrimes(i)) { coun++ } } return coun}; 我们可以看到函数逻辑比较简单,内层isPrimes函数为了提高速度,给除数加了一个小于等于Math.sqrt(num)的限制,之所以可以用这个数字来做限制是因为:num = a * b 当a增大的时候b一定减小,我们假设a从1一直增加,那么b将从num一直减小,当到a = Math.sqrt(num)的时候,a == b ,如果此时a继续增大呢,a是不是就向刚才一直减小的b一样了,也就是说我们相当于把之前做的运算又从新做了一遍,而这个计算是没有意义的,所以如果一个数除到他的开跟都不能整除,基本可以判定他是一个素数了。 进阶版12345678910111213141516171819var primesList = [] function isPrimes(num) { for(var j = 0; primesList[j] <= Math.sqrt(num); j++) { if(num % primesList[j] == 0){ return false } } return true}var countPrimes = function(n) { var coun = 0 for(var i =2; i < n; i++) { if(isPrimes(i)) { primesList.push(i) //给数组添加质数,丰富质数表 coun++ } } return coun}; 我们看一下上面的函数,上面函数的思路是这样的:一个数(大于1),他不是质数(素数)就是合数,合数可以分解成几个质数相乘,那么我是不是只要用这个数去除以质数我就知道他是不是一个合数了,那么问题来看了,一个数我们记作A,我们只需要依次他除以[2,√A]之间的质数就能判断出来他是不是一个合数了,这样子比我们从[2,√A],一个一个除要快很多,好了现在问题来了,我们是不是需要一个[2,√A]之间的质数表,上面的程序是这样子构建这个质数表的,从2开始,一边判断一边添加,这样子后面的数字就可以用前面的质数表了(实际上一个质数的平方是远大于紧跟在在后面的那个质数的),我们现在回到程序(其实单步跟一下程序就能看出来啦)。1234if(isPrimes(i)) { primesList.push(i) //给数组添加质数,丰富质数表 coun++}1 这个语句作用是,如果发现一个数是质数就给他放到质数表里,然后在记数结果+112345678function isPrimes(num) { for(var j = 0; primesList[j] <= Math.sqrt(num); j++) { if(num % primesList[j] == 0){ return false } } return true} 这个函数是判断函数啦,需要注意的是,第一次计算的时候primesList[0] == undefine ,num % primesList[j]的结果是NAN(我更喜欢叫他是无意义的计算),然后NAN !== 0 (NAN连自己都相等) 这样子第一质数2,就成功的放入了数组啦我们又成功地优化了函数,不禁要问这样子还可以优化吗?答案是:必须可以啊。 进阶版小优化我们给上面函数的 countPrimes 函数改一下12345678910var countPrimes = function(n) { var coun = 1 for(var i =3; i < n; i+=2) { if(isPrimes(i)) { primesList.push(i) //给数组添加质数,丰富质数表 coun++ } } return coun};我们把coun 初始值改成1,变量i从3开始,每次都往里放奇数(偶数绝逼是合数),这样子速度又快了不少 再进阶版虽然上面的好理解,而且有了一定的优化,但是效率并不高,那么有没有效率更高的呢,答案是必须的,我们来看一下几千年前的一个算法:埃拉托斯特尼筛法其实 埃拉托斯特尼筛法 简单的说就是,把[2,A]之间的[2,√A]的数的所有倍数全部划去,最后留下的就是质数。那么我们是不是可以这样子生成一个大小为n的数组,数组全部都为1,每发现一个合数,我们就把一个数组的元素变为0,最后我们只需要统计1的个数就好了12345678910111213141516171819202122232425function countPrimes(n) { //我们声明一个大小为n的数组,并且全部标记为1(我们把标记1是质数,0标记合数), var flags = new Array(n).fill(1) //其实这里的想法是 0 1 全不是质数,所以打掉, flags[0] = flags[1] = 0 var sn = Math.sqrt(n) //我们只比对到[2,√A]的所有倍数 for(var i = 2; i <= sn; i++) { //注意在循环里面我们已经操作了flags,所以我们此时不需要再判断划掉了的元素(flags[i] == 0) if (flags[i]) { //注意我们这个j,埃拉托斯特尼筛法 是从数字的倍数开始划的 for(var j = i * i; j < n; j += i) { flags[j] = 0 } } } var count = 0 for(var i = 0; i<n; i++) { if(flags[i]) { count++ } } return count}现在我们又GET了一个新技能,我们再想一下是不是还可以优化一下,答案依然是是的,我们看一下他的进阶版 再再进阶版如果你有心的话,你会发现我们上一个版本的函数,在划去合数的时候,会有重复划去的过程,这个我也就不上图了,自己单步走一下,或者在纸上画一下一切就会浮现出来的。我们先上函数12345678910111213141516171819202122//小于3 就是 0 1 直接标记为0var countPrimesx = function(n) { if (n < 3) { return 0 } //数组全部置1 var f = new Array(n).fill(true)//有一半的数字为偶数,所以直接打掉一半,然后后面的或是为了取整 var count = n / 2 | 0 for(var i = 3; i * i < n; i += 2) { for(var j = i * i; j < n; j += 2*i) { if (f[j]) { --count f[j] = false } } } return count} 文章末尾感谢那些愿意分享知识的人:谢大喵TanX的博客]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>算法</tag>
<tag>leet</tag>
<tag>素数</tag>
</tags>
</entry>
<entry>
<title><![CDATA[JavaScript的递归以及浅谈尾调用]]></title>
<url>%2F2018%2F07%2F03%2FJavaScript-tail-Call%2F</url>
<content type="text"><![CDATA[一个递归引发的血案案发现场今天看到了递归,测试的时候必须是经典的 Fibonacci (斐波纳契) 数列,然后我做的时候的代码如下:1234function Fibonacci (n) { if ( n <= 1 ) {return 1}; return Fibonacci(n - 1) + Fibonacci(n - 2);}这是一个很简答的递归函数,单纯且不做作。他很简单,看一眼就知道他是如何运算的,单纯到到计算一个Fibonacci(100)就给我来个栈溢出错误(stack overflow),然后我很奇葩的算了一下Fibonacci(25),然后就卡-住-了,这不行啊,所以我就去搜原因去咯。 抢救现场找了一下,找了一个有优化效果的函数:尾递归优化后的程序源程序连接1234var fibArr =[0,1,1];function Fibonacci(n){ return fibArr[n]? fibArr[n]:(fibArr[n]=Fibonacci(n-1)+Fibonacci(n-2));} 案件复盘嗯,解释这个程序的思想之前我们先来看一下我们以前的程序都干了什么,在这之前我们先来补充一个小知识点:我们知道,函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。 @阮一峰es6.ruanyifeng.com/?search=%E9%80%92%E5%BD%92&x=0&y=0#docs/function通过上面我们知道了,要是每次调用都会在内存生成一个调用帧,然后我们看一下Fibonacci数列,我们单步进入程序的时候(或者在纸上画一下)可以发现,我们一开始的程序在计算的时候会压入很多重复的计算,也就是说很多调用帧的返回结果是相同的,但是我们还是把他们压入到了调用栈里面,(函数先计算+左边的,然后就不断的进入函数内部,不断的压栈,计算完成后再一层一层的往回出栈,等到+左边的计算完了,再来右边的,你会发现右边的很多调用帧的结果刚才都算出来了,可是在算+左边结果的时候又把它们清除了,这样子是不是浪费了大把的时间)这样一来就是两个结果,栈不够用爆掉啦,栈将将够用,然后程序慢慢进再慢慢的出,这时候好的电脑运行会变慢,差的电脑就会卡住或者死机,让我哭一会。 引入尾调用我哭好了,我们继续看优化后的函数,优化后的函数优化就是优化了重复的那个一部分,我们用数组来存储+左边我们每一个调用帧计算的结果,到计算+右边的时候我们直接和数组里面的数字(注意那个n)进行比对,准确的说是看参数是否相同,相同的话就直接出返回结果而不进栈了。这里其实用到了一点缓存区的概念(这个我们有空再聊哈),我们这样子优化的直接效果就是进去的调用帧少了,直接结果是栈不会爆了,也没有了多余的重复计算,速度直接就上去了。那么问题来了,是不是递归都会有这个问题,答案是:一些形式的递归是的,这个由JavaScript的栈机制造成的。是不是要说,一些形式是的,那不就是还有形式不是,好了,我要开始装逼了,那个形式就是:尾调用。直接上阮一峰大佬的解释:尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。 123function f(x){ return g(x);}上面代码中,函数f的最后一步是调用函数g,这就叫尾调用。以下三种情况,都不属于尾调用。 12345678910111213141516// 情况一function f(x){ let y = g(x); return y;}// 情况二function f(x){ return g(x) + 1;}// 情况三function f(x){ g(x);}上面代码中,情况一是调用函数g之后,还有赋值操作,所以不属于尾调用,即使语义完全一样。情况二也属于调用后还有操作,即使写在一行内。情况三等同于下面的代码。 1234function f(x){ g(x); return undefined;}尾调用不一定出现在函数尾部,只要是最后一步操作即可。 123456function f(x) { if (x > 0) { return m(x) } return n(x);}上面代码中,函数m和n都属于尾调用,因为它们都是函数f的最后一步操作。 @阮一峰es6.ruanyifeng.com/?search=%E9%80%92%E5%BD%92&x=0&y=0#docs/function#%E5%B0%BE%E8%B0%83%E7%94%A8%E4%BC%98%E5%8C%96 关于尾调用的优化好了现在知道了尾调用,按道理我应该引入尾调用的优化,毕竟ES6第一次明确规定,所有 ECMAScript 的实现,都必须部署“尾调用优化”。这就是说,ES6 中只要使用尾递归,就不会发生栈溢出,相对节省内存。也就是说,尾调用是一写法形式,写成这样子,浏览器会自动进行优化(不过目前只有苹果的才支持,其它的浏览器需要在严格模式下才执行这个操作),又或者我们可以写一个函数,自己来做这个尾调用优化,但是我依稀还记得 Eloquent_JavaScript(第二版) 中有一句话:The dilemma of speed versus elegance is an interesting one. You can see it as a kind of continuum between human-friendliness and machinefriendliness. Almost any program can be made faster by making it bigger and more convoluted. The programmer must decide on an appropriate balance. Marijn HaverbekeEloquent_JavaScript其实自己进行优化的方式也只是把递归转化成循环的样子,有的人会坚持尽可能的用循环而不是用递归,应为为达到同样的效果用循环更快,其实二者那个好都说不好的,或许等到浏览器都支持在正常模式下也进行尾递归优化的时候,递归就用的越来越多了,毕竟他有其独到的优势哈。 递归函数的规则最后附上一个写递归函数的规则:当编写递归例程的时候,关键是要牢记递归的四条基本法则: 基准情形。必须总有某些基准情形,它无须递归就能解出。 不断推进。对于那些需要递归求解的情形嗯每一次递归调用都必须要使求解状况朝接近基准情形的方向推进。 设计法则。假设所有的递归调用都能运行。 合成效益法则(ωmpound interest rule ) 。在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作。 Mark Allen Weiss·著 冯舜玺·译数据结构与算法分析:C语言描述(第2版) 以下是本博文参考的资料,感谢他们的分享 数据结构与算法分析:C语言描述(第2版)阮一峰大佬的:ECMAScript 6入门phpstudy的文章jxgz_leo的博客。关于尾数调用优化,这个博文写的比阮大佬能详细]]></content>
<categories>
<category>JavaScript</category>
</categories>
<tags>
<tag>JavaScript</tag>
<tag>递归</tag>
<tag>栈</tag>
</tags>
</entry>
<entry>
<title><![CDATA[发现个异或的妙用]]></title>
<url>%2F2018%2F07%2F02%2FSingle-Number%2F</url>
<content type="text"><![CDATA[有个题目是这样子的:Single Number题目要求如下:Given a non-empty array of integers, every element appears twice except for one. Find that single one.Note:Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?意思就是一个数组[2,2,3,3,5] 5就是那个 single numble了然后自己想了半天也就会笨办法,倒也能通过,然后看了一下前面人的解法,又一次打开了脑洞大佬的代码如下:12345678910var singleNumber = function(nums) { if (!nums || nums.length === 0) { throw new Error(); } var res = nums[0]; for (var i = 1; i < nums.length; i++) { res ^= nums[i]; } return res;};一开始我还没有看懂为什么异或就可以,不就是相同为0,不同为1啊,然后单步进去运行了一下,还是一头雾水(单步的时候res没有规律),出去上个厕所,喝口水。然后突然想到,从把数组所有的数字全拿出来,一个一个异或,可以看成相同的和相同的异或,然后得到的是0 ,最后剩下一个奇数的single number,把他和0异或(^)就得到他本身啊。 多动动,多喝水,没事上个厕所,买个小黄鸭,换个角度,问题就迎刃而解啊啊啊啊啊啊!!!!]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>算法</tag>
<tag>leetcode</tag>
<tag>思路</tag>
</tags>
</entry>
<entry>
<title><![CDATA[从Power_of_Two所得]]></title>
<url>%2F2018%2F07%2F02%2Fleetode-Power-of-Two-think%2F</url>
<content type="text"><![CDATA[开始刷leetcode上的题目了,毕竟写程序也是需要开脑洞的,刷题目就能让自己脑洞越来越大的说,这不发现了一个题目: Power of Two题目要求:Given an integer, write a function to determine if it is a power of two.其实就是让你看一个数是不是2的幂次方 先说我的思路吧,一个数一直除以2,除到他小于4的时候,2的幂方数就是只有 2 1 这两个数字了,那么我判断一下是不是他俩就好啦123456789101112131415161718192021var isPowerOfTwo = function (n) { var wx = n var falg = 0 while (falg == 0) { // wx = wx >> 1 wx = wx / 2 if (wx < 4) { //需要考虑一开始就是1的情况 if (wx == 2 || wx == 1 || wx == 0.5) { falg = 1 // console.log("true") return true } else { falg = 2 // console.log("false") return false } } }}; 然后看了看别人的代码,发现了一个很棒的思路,思路就是看 n 与 n-1 与出来的结果是不是 0我们看一下 4 二进制是:0100 那么3呢,3是 0011,二者与出来就是0,所以这个思路太赞了,一下子就得出结果了。代码是没有的,思路都有了,代码还写不出来吗! 又发现了个看数字是不是4的幂的题我的想法是 先看他是不是2的幂,再看他是不是小于10,小于的话,等不等于 4 或者 8然后发现了一个想法是,先看是不是2 的幂,然后看能不能整除4然后又发现了个是不是3的幂的数,我的思路是利用数学规则(各个位相加为三的倍数)看他是不是能被3整除,能的话就除以3,用结果继续这样子判断,一直到他小于10的时候,看是不是 3 或者 9结果发现了一个更惊为天人的思路,思路是这样子的,把可以取值范围内的最大3的幂数求出来,记为 a , 然后给个数字b 如果 a % b === 0那b就是3的幂数,没有想到的话看下面123a = 3 * 3 * 3 * 3 * 3 *3 *3 b = 3 * 3 * 3 c = 3 * 3 * 4 这个就很直观了吧!]]></content>
<categories>
<category>leetcode</category>
</categories>
<tags>
<tag>算法</tag>
<tag>leetcode</tag>
<tag>思路</tag>
</tags>
</entry>
<entry>
<title><![CDATA[给文章加入版权信息]]></title>
<url>%2F2018%2F07%2F02%2Ftip-copyright%2F</url>
<content type="text"><![CDATA[看到别人的的博客下面都有版权信息(就是本文最底下的那个啦),然后自己也想加上一个,搜了一下都是17年的老文章,用的是自定义的方法。本来打算去DIY一下,然后突发奇想去主题插件搜了一下版权(copyright),然后发现了这个东西123post_copyright: enable: false..... 就把那个enable: false 改成enable: true 就好啦` ps:如果底下的版权信息中的本文链接:成了http://yoursite.com/2018/07/02/tip-copyright这个样子只需要在网站配置文件下把url: http://yoursite.com 改成url: https://fengmumu1.github.io 就好啦 有一篇博文还可以,就是关于next配置的,不过文章写的时间有点老,方法都还是有效果的,不过新的next版本会有更好的实现方式,所以不要以为的抄啦。 文章传送门]]></content>
<categories>
<category>hexo</category>
</categories>
<tags>
<tag>hexo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[JavaScript中的数字存储]]></title>
<url>%2F2018%2F06%2F30%2Fjs-number%2F</url>
<content type="text"><![CDATA[JavaScript中数字是不区分整数值与浮点数值的,在JavaScript中所有的数均使用64位的浮点格式来存储和表示(IEEE 754标准)。所以数值最大是:±1.7976931348623157 X 10^308,最小是±5X10^-324,可以表示的整数范围是-9 007 199 254 740 992 ~ 9 007 199 254 740 992 (对应的是-2^53~2^53)包含边界值。 注意这里说的最大/小,准确的应该说是:在正数和负数范围内可以准确得到的最大最小的数 比如1.7976931348623157 X 10^308 是可以得到的最大的正数,也就是 JavaScript 中的MAX_VALUE,任何大于这个的在 js 中都是 Infinity,需要注意的是,他的负数,从数学上可以说是最小值,但是在存储上并不是最小的值 而 5X10^-324 是可以得到的最小的 最接近于 0 的最小的值,js 中的 MIN_VALUE 的值约为 5e-324。小于 MIN_VALUE (“underflow values”) 的值将会转换为 0, 注意,当这个数值表示为负数的时候 他是负数范围内最大的数值 注意了啊,上面的有隐藏的问题的,结尾有相关的解释哈注意:在对JS中的数值进行位操作的时候会自动把64位转化为32进行操作(由于运算符的自身限制,其只能对32位进行操作),在对小数进行位操作 比如左移零位,小数会丢弃小数部分转化成整数, 所以以后看到 1.25 >> 0,就知道大佬是想做一个取整操作啦 这里尤其注意的一点通过位运算来做取整操作,会有溢出风险,数值会变,所以请谨慎使用 。 JavaScript中数字不一定很准确首先我们先看一段代码123456var x = 0var y = 0x = .3 - .2y = .2 - .1console.log(x == .1 ) // falseconsole.log(y == .1 ) // true运行结果是 false 和 true讲道理的说0.3 - 0.2 = 0.1;0.2-0.1 = 0.1 这个是正确的,那么为什么到了JS的代码里就不正确了,解决这个问题,我们首先要看一下JS的数字是如何存储的。 基础知识点补充 进制的转换 JS数字的存储在本文的前言中我们说到了JS用的是IEEE754标准,这个标准规定了浮点数的表示方法(此方法也是目前通用计算机所才用的浮点数存数方式)。在此标准中浮点数有float和double两种存储形式,但是JS的数字只采用了double类型来做存储,也就是我们常说的使用64位来存储数字的双精度型。那么我们是如何利用这64位来存储数据的呢? 我们都知道科学计数法,即把一个数比如123465.555可以写成1.23456555*10^5,这样子不仅读写方便也能减少存储该数字的空间,123456.555是一个十进制的数字,那么我们是把一个二进制的数字是否也可以转化成这个形式,以达到减少存数空间的目的,答案是肯定的。我们把一个十进制数比如:16.25 写成二进制的形式:10000.01,类比十进制的写法,我们可以把他写成 1.000001X2^4,现在我们看一下这个数字,他由有效数字 1.000001 以及指数 2^4 以及我们省略了的符号位组成(正数的符号位是 + 负数的是- 零的话严格来说不属于正负,计算机如何处理他我们后文将解释),那么64位的空间我们就知道需要放三大块的东西了:有效数字、指数、符号位 sign bit(符号):我们在64位的最高位放置符号位,最高位为1,表示数字是正数还是负数 exponent(指数): 我们在从左往右再取11位用来表示指数 mantissa(尾数): 我们把剩余的52位空间全部用来存储有效数字 1.为了最大限度的利用存储有效数字的52位,我们把小数点以及小数点前的那一个数字给省略掉(正确的化简后尾数会被处理到大于等于1而小于2的区间内,这时候便可省去前导的“1”),所以我们只需要存贮小数点后面的 000001就可以了2.在上图中存储指数的数值叫做阶码,有它转换出来的阶码的数值等于指数的数值,阶码=指数+1023 (科学计数法中的指数是可以为负数的,所以约定减去一个中间数 1023,[0,1022] 表示为负,[1024,2047] 表示为正)。在 ECMAScript 规范里有给出指数的范围: [-1074, 971] 。 为什么会出现数字不准确现在我们知道了一个数是如何存储的,那么我们来想一个问题,1.3 转化为二进制是多少0.010011001100....1100,对的你发现了他的小数部分除不尽,那么意味着他的小数部分用64位表示不完。我们来看一下浏览器是如何处理的。12var a = 1.3console.log(a.toString(2)) 输出的结果是 1.010011001100110011001100110011001100110011001100110011我们来比较一下浏览器计算的1.3和我们手算的1.3的差别12浏览器: 1.0100110011001100110011001100110011001100110011001101手 算 : 1.0100110011001100110011001100110011001100110011001100*1100* 我们看到浏览器进行了进位操作,浏览器执行的是满1进位,不满则省略的方案所以这也就是为什么我们在进行浮点数运算的时候有时得不到精确的数值的原因所在了。 为什么 0.3 == 0.312var x = 0.3console.log( x === 0.3 ) 它的运行结果是true前面不是说使用浮点数存储,小数部分出现循环后,系统存的不是一个准确数值,那么这里为什么会是true呢?因为 尾数(mantissa) 固定长度是 52 位,再加上省略的一位,最多可以表示的数是 2^53=9007199254740992,对应科学计数尾数是 9.007199254740992,这也是 JS 最多能表示的精度(也就是说按照52个尾数全为0到其全为1,让其对应以十进制表示的从1到9007199254740992 注意我们省略了小数点前面的一位,所以计算的时候应该按照53位计算)。它的长度是 16,所以可以近似使用 toPrecision(16) 来做精度运算,超过的精度会自动做凑整处理。于是就有 x.toPrecision(16) === 0.3toPrecision(16) 是先把二进制保存的不精确的那个数,转化为十进制数。然后是对十进制的数字再去保留小数点后的16位 大数危机如果有数字处于2^53到2^63之间呢,他们是是如何取舍的 (2^53, 2^54) 之间的数会两个选一个,只能精确表示偶数 (2^54, 2^55) 之间的数会四个选一个,只能精确表示4个倍数… 依次跳过更多2的倍数我们来看一张图(图是我偷得) 我们可以看到在中间的部分,实数与浮点数还可以近似的一一对应,越往两边用浮点数与实数对应关系就越差,也就是说精度就逐渐的丢失 要想解决大数的问题你可以引用第三方库bignumber.js,原理是把所有数字当作字符串,重新实现了计算逻辑,缺点是性能比原生的差很多,所以原生支持大数就很有必要了。TC39 已经有一个 Stage 3 的提案proposal bigint,大数问题有望彻底解决。在浏览器正式支持前,可以使用Babel 7.0 来实现,它的内部是自动转换成 big-integer 来计算,这样能保持精度但运算效率会降低。 @camsongzhuanlan.zhihu.com/p/30703042 toPrecision 和 toFixed toPrecision 是处理精度,精度是从左至右第一个不为0的数开始数起。 toFixed 是小数点后指定位数取整,从小数点开始数起。两者都能对多余数字做凑整处理,也有些人用 toFixed 来做四舍五入,但注意它是有坑的。比如1.055.toFixed(2) = 1.05 问题是他的第三位明明是5啊,说好的四舍五入呢?因为1.055实际对应的数字是1.0499999999 所以就出现前面的结果啦当你拿到 1.4000000000000001 这样的数据要展示时,建议使用 toPrecision 凑整并 parseFloat 转成数字后再显示。对于运算类操作,如 +-*/,就不能使用 toPrecision 了。正确的做法是把小数转成整数后再运算。ps: 1.以上内容是原文章的删减内容,需要看原文章内容,下面有链接 2.toPrecision 取一个经验数值 12 即可 3.原文推荐了一个js处理浮点数的类库,大小只有1K,传送门: number-precision @camsongzhuanlan.zhihu.com/p/30703042 现在我们继续看这样一行代码19999999999999999 == 10000000000000000 结果是true,这个又是为什么呢?我们在前面说到e的范围是 [-1074, 971] ,也就是说他能保存的最大的数字是1 x (2^53 - 1) x 2^971 = 1.7976931348623157e+308 52个1就等于 2^53 - 1 注意结果要补上我们省略的那个1. 类似的整数部分最小的是:1 x 1 x 2^(-1074) = 5e-324由此我们可以知道:Number.MAX_VALUE 以及 Number.MIN_VALUE 的两个数值了注意:Number.MIN_VALUE 只是正数中最小的数字,实数最小的数字是 -Number.MAX_VALUE 现在结合前面所有的知识回过头来看一下,js中最大的数字是 Number.MAX_VALUE ,他是尾数为 2^53 指数为971 时候的数字那么 如果有个数值他转成二进制的科学计数法之后,尾数大于2^53次方呢,这时候由于计算机会有一定的取舍(前文已经说过,具体的取舍方法有四条,有兴趣的可以自行维基解密),所以他的存储就有了误差。所以经过了取舍的两个大数就相同了, 注意:其实现在我们可以发现在浮点数的时候虽然最大是 Number.MAX_VALUE,但是他有可能是其他的数值取舍得来,所以小于2^53的数值才是可以正确表示的数值,所以就有了 Number.MAX_SAFE_INTEGE 这个数值,其表示js中的安全数值 最后八卦几个数值9007199254740990 (that is, 2^53-2) distinct “Not-a-Number” values of the IEEE Standard are represented in ECMAScript as a single special NaN value. (Note that the NaN value is produced by the program expression NaN.) In some implementations, external code might be able to detect a difference between various Not-a-Number values, but such behaviour is implementation-dependent; to ECMAScript code, all NaN values are indistinguishable from each other. @ECMAScript 规范es5.github.io/#x8.5 NAN = 9007199254740990 == 2^53−2 需要注意,NAN只是数值上是这个,但实际上他是有程序生成的所以所以NAN不等于NANHA 关于无穷大有个有意思的东西首先抛出大佬给的问题(原始博文在最底部)1234567891011Number.MAX_VALUE + 1 == Number.MAX_VALUE;Number.MAX_VALUE + 2 == Number.MAX_VALUE;...Number.MAX_VALUE + x == Number.MAX_VALUE;Number.MAX_VALUE + x + 1 == Infinity;...Number.MAX_VALUE + Number.MAX_VALUE == Infinity;// 问题:// 1. x 的值是什么?// 2. Infinity - Number.MAX_VALUE == x + 1; 是 true 还是 false ? 放出原博主的解答:我的想法是这样的: Number.MAX_VALUE.toString(16) = ”fffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000″ 前面有 13 个 f, 二进制就是 52 个 1还有一个 8, 二进制是 1000也就是说,前面 53 位都是 1 这样,当 Number.MAX_VALUE + 1 时,1 替代最后一个 0,但 IEEE 754 双精度浮点数的 m 最大为 53(含隐藏位),因此添加的 1 在存储时会被舍弃掉,所以: Number.MAX_VALUE + 1 == Number.MAX_VALUE 同理类推,当 8(1000) 变成 b(1011),b 后面的位取最大值时,依旧有: 0xfffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff == Number.MAX_VALUE 进一步,当 再增 1, b 变成 c 时,将发生质变: 0xfffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 == Infinity 这是因为前面将有 54 个连续的 1, 在存储时,exponent 将由971 变成 972, 超出了 IEEE 754 双精度浮点数存储格式中 e 的最大值,因此质变为 Infinity 了。 这样,题目中 x 的值就很容易得到了: x = 0xfffffffffffffbffff… – 0xfffffffffffff80000…= 0x00000000000003ffff… 注意这个数在IEEE 754 双精度浮点数格式下无法精确存储。 还能得到两个有趣的结论: Number.MAX_VALUE 不是一个数,而是一个区间 [0xfffffffffffff80000…, 0xfffffffffffffc0000…) Infinity 指的是,所有大于等于 0xfffffffffffffc0000… 的数。 @lifesingerlifesinger.wordpress.com/2011/03/07/js-precision 更新一个 Number.EPSILON 知识点: Number.EPSILON 是 JS 里面 规定的 数值的最小精度,不是一个整数,是 它表示 1 与大于 1 的最小浮点数之间的差, 谢谢下面大佬指正 补充两个进制转换知识点吧,嗯,严格的来说是一个知识点,话不多说,直接上图 参考文档 谢大喵的上课视频 知乎:抓住数据的小尾巴 - JS浮点数陷阱及解法 https://zhuanlan.zhihu.com/p/30703042 lifesinger的博客 https://lifesinger.wordpress.com/2011/03/07/js-precision/ ECMAScript 规范 http://es5.github.io/#x8.5 进制转换 https://www.cnblogs.com/xkfz007/articles/2590472.html]]></content>
<categories>
<category>JavaScript</category>
</categories>
<tags>
<tag>JavaScript</tag>
<tag>数字</tag>
<tag>存储</tag>
</tags>
</entry>
<entry>
<title><![CDATA[hexo下的markdown语法]]></title>
<url>%2F2018%2F06%2F29%2Fhexo-markdown-grammar%2F</url>
<content type="text"><![CDATA[入坑了一个新的主题-next,发现他有一些markdown的语法比较特殊,所以整理了一下相关的信息。 markdown语法文章头部的 front-matter目前我用的主题是next,版本是:v5.1.4 ,hexo的版本是3.7.1123456title: hexo下的markdown语法date: 2018-06-29 20:53:40tags: - hexo - markdown语法categories: hexo 以前的tages的写法是 tags: [aa,bb,cc] ,现在我发现tages的写法是:隔行然后缩进前面加中划线,再加上一个空格,然后写上标签。注意:tags 与后面的标签内容必须要有一个空格,在hexo中的很多地方都有这个要求 文章相关的语法标题123===== (等于号)是一级标题------ (减号)是二级标题### 是三级标题 或者使用传统的12345# H1## H2### H3...###### H6 分割线单独一行使用***或者——————(下划线) 删除线使用~~需要删除的文字~~来表示,这个要被删除注意:前后~~与文字没有空格 超链接1[链接的文字](链接的地址 "鼠标指上后链接显示的文字") 注释用\来注释,类似于转义字符的效果 引用1> 打工是不可能打工的,这辈子都不可能打工的 注意:如果仅在第一行使用 >, 后面相邻的行即使省略 >,也会变成引用内容,可以在结束的语句后面加上两个空格,或者与后面的语句直接空一行 验证写法12345> 打工是不可能打工的,这辈子都不可能打工的打工是不可能打工的,这辈子都不可能打工的 打工是不可能打工的,这辈子都不可能打工的 打工是不可能打工的,这辈子都不可能打工的 效果 打工是不可能打工的,这辈子都不可能打工的打工是不可能打工的,这辈子都不可能打工的打工是不可能打工的,这辈子都不可能打工的 打工是不可能打工的,这辈子都不可能打工的推荐使用后面说的内置标签来引入,效果更好使用>的嵌套格式,没有效果 列表列表有无序和有序之分,考虑到用实际使用无序列表居多,这里只介绍无序列表,无序列表使用空格的缩进来表示层级,+和- 都是他的关键字符,此外给-/+ 和文字中间加入 [ ] 可以有计划表的效果写法123456+ 计划A + [ ] A计划第一步 + [x]首先XXX- [ ] 计划B - [ ] B计划第一步 - [x]首先XXX效果 计划A A计划第一步 首先XXX 计划B B计划第一步 首先XXX 注意:关键字符与文字要有空格,[]中间要用空格打开,否则不生效 插入图片1 Alt text:图片的Alt标签,用来描述图片的关键词,可以不写。最初的本意是当图片因为某种原因不能被显示时而出现的替代文字,后来又被用于SEO,可以方便搜索引擎根据Alt text里面的关键词搜索到图片。 图片链接:可以是图片的本地地址或者是网址。 “optional title”:鼠标悬置于图片上会出现的标题文字,可以不写。 @tahrwww.zhihu.com/question/21065229/answer/132993179 原生的语法使用效果不好,推荐使用后面hexo以及next的插入图片对应标签语法 表格使用|来分隔不同的单元格,使用-来分隔表头与其他行写法1234| 名字 | 性别 | 年龄 || ---- | ---- | --- || 张三 | 男 | 18 || 赵淑芬 | 女 | 20 |效果 名字 性别 年龄 张三 男 18 赵淑芬 女 20 注意:为了使 Markdown 更清晰,| 和 - 两侧需要至少有一个空格(最左侧和最右侧的 | 外不需要) 如果想改变表格的对齐方式:需要在表头下方的分割线标记中加入 :此外,表格中可以放其他的markdown的标记 :— 代表左对齐 :–: 代表居中对齐 —: 代表右对齐 默认是左对齐写法1234| 名字 | 性别 | 年龄 || ----: | :----: | :--- || 张三 | 男 | 18 || 赵淑芬 | 女 | 20 | 效果 名字 性别 年龄 张三 男 18 赵淑芬 女 20 hexo 的标签语法hexo 为了显示的效果更好,自身定义了一些标签插件,hexo中文文档链接 引用块123{% blockquote [author[, source]] [link] [source_link_title] %}content{% endblockquote %} 普通的引用在blockquote后面不写任何参数,就只是单纯的引用,效果与使用>一样 对书上语言的引用123{% blockquote 作者, 出处 %}xxxxxxxxxxxxxxxxxxxxxxxxxxxx{% endblockquote %} 黑夜无论怎样悠长,白昼总会到来。 莎士比亚麦克白 对网络上的引用123{% blockquote @作者 网络地址 %}xxxxxxxxxxxxxxxxxxxxxxxxxx{% endblockquote %} 有时候,“爱国”,是一个空洞的词语。更多的人是在言语里,在诗歌里”爱国“,他们没有一点点实际行动,甚至充满抱怨。 @余秀华blog.sina.com.cn/yuxiuhua1976 代码块123{% codeblock [title] [lang:language] [url] [link text] %}code snippet{% endcodeblock %} 普通代码块在codeblock不加任何参数的标签,和使用`(单行的时候使用)以及` ` `(多行的时候使用)效果一样123{% codeblock %}console.log("我叫丰木木"){% endcodeblock %} 1console.log("我叫丰木木") 带有使用语言的代码块(有高亮)123{% codeblock lang:JavaScript %}console.log("我叫丰木木"){% endcodeblock %} 1console.log("我叫丰木木") 带有说明的代码块123{% codeblock js控制台输出语句 %}console.log("我叫丰木木"){% endcodeblock %} 控制台输出语句1console.log("我叫丰木木") 附带有说明网址的代码块123{% codeblock 控制台输出语句 https://developer.mozilla.org/zh-CN/docs/Web/API/Console/log 查看MDN相关解释%}console.log("我叫丰木木"){% endcodeblock %} 控制台输出语句查看MDN相关解释1console.log("我叫丰木木") 反引号代码块使用``` [title] [lang:language] [url] [link text] ``` 一样可以使用以上几个标签效果注意:反引号代码块后面的参数 在本博客环境下实测没有效果,也就是说使用`是可以当做普通代码块使用 插入iframe1{% iframe url [width] [height] %} 插入image1{% img [class names] /path/to/image [width] [height] [title text [alt text]] %} 插入Include Code插入source文件夹中的代码文件1{% include_code [title] [lang:language] path/to/file %} next中的标签next文档中文传门 文本居中123456789<!-- HTML方式: 直接在 Markdown 文件中编写 HTML 来调用 --><!-- 其中 class="blockquote-center" 是必须的 --><blockquote class="blockquote-center">blah blah blah</blockquote><!-- 标签 方式,要求版本在0.4.5或以上 -->{% centerquote %}blah blah blah{% endcenterquote %}<!-- 标签别名 -->{% cq %} blah blah blah {% endcq %} 当我看到人和草木一样生长繁衍,任凭同一个老天他们鼓励阻拦。青春时蓬蓬勃勃,全盛时又该走向凋落,繁华和璀璨都将从记忆中消散。——Shakespeare 《莎士比亚十四行诗》 插入的图片变大使用方式 HTML方式:使用这种方式时,为 img 添加属性 class=”full-image”即可。 标签方式:使用 fullimage 或者 简写 fi, 并传递图片地址、 alt 和 title 属性即可。 属性之间以逗号分隔。突破容器宽度限制的图片文档链接1234567891011<!-- HTML方式: 直接在 Markdown 文件中编写 HTML 来调用 --><!-- 其中 class="full-image" 是必须的 --><img src="/image-url" class="full-image" /><!-- 标签 方式,要求版本在0.4.5或以上 --><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="/image-url" class="full-image" alt="alt" title="title" /><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span><!-- 别名 --><span itemprop="image" itemscope itemtype="http://schema.org/ImageObject"><img itemprop="url image" src="/image-url" class="full-image" alt="alt" title="title" /><meta itemprop="width" content="auto"><meta itemprop="height" content="auto"></span> Bootstrap Callout123{% note class_name %} xxxxxxxxxxxxxxxxxxx {% endnote %} class_name 数值可以为 default primary success info warning danger]]></content>
<categories>
<category>hexo</category>
</categories>
<tags>
<tag>hexo</tag>
<tag>markdown语法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[第一个文件]]></title>
<url>%2F2018%2F06%2F28%2Ffist%20document%2F</url>
<content type="text"><![CDATA[第一个文件浪费了大半天,试着用hexo在github上建了一个博客,就一个感觉:小屏幕太毁眼睛了目前先这样后期有如下安排 熟悉hexo 修改目前正在使用的appollo模版 写学习笔记]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>杂谈</tag>
</tags>
</entry>
</search>