Project Euler Problem 71 and Stern-Brocot tree
Project Euler Problem 71 describes as follows:
Consider the fraction, n/d, where n and d are positive integers. If n < d and HCF(n,d)=1, it is called a reduced proper fraction.
If we list the set of reduced proper fractions for d ≤ 8 in ascending order of size, we get:
1/8, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 3/8, 2/5, 3/7, 1/2, 4/7, 3/5, 5/8, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 7/8
It can be seen that 2/5 is the fraction immediately to the left of 3/7.
By listing the set of reduced proper fractions for d ≤ 1,000,000 in ascending order of size, find the numerator of the fraction immediately to the left of 3/7.
Such sequences can be included to be a Stern–Brocot tree
It all starts with fractions and the number line. We start off with the interval [0,1]:
Now let’s play a little game. We’re going to take the fractions 0/1 and 1/1 and calculate their mediant by taking the sum of their numerators and denominators to get (0+1)/(1+1)=1/2:
With this new point on the line, we can do this mediant operation again to get (0+1)/(1+2)=1/3 and (1+1)/(2+1)=2/3:
Another iteration of this process gives:
But we can continue this process indefinitely! And instead of notating these fractions on the number line, we can put them into a tree:
Now of course, merely having fractions between zero and one isn’t satisfying enough, so we extend the construction of this tree to begin with the points 0/1 and 1/0, as nonsensical as that may sound. Then we get something like this:
This is the Stern-Brocot tree.
Here we use the subtree which root is 1/2:
We need to find a node between 2/5 and 3/7. first, take numerators as [2, 3], denominators as [5, 7]
so we can find a node between 2/5 and 3/7, that is $\frac {2+3} {5+7} = \frac 5 {12}$
. Then iteratively we use the same strategy to find a node between 5/12 and 3/7. When we reach the condition that denominator > 1000,000, loop terminates.
Here is the code using coffeescript:1
2
3
4
5
6
7[n, d] = [2, 5]
while d <= 1000000
n += 3
d += 7
# go back if we exceeds
console.log n - 3
Reference: http://hxhl95.github.io/stern-brocot-tree-part-1/
事实上,可以证明:
如果$\frac a b < \frac c d$
,则$\frac a b < \frac {a+c} {b+d} < \frac c d$
证明如下:
由$\frac a b ①< \frac c d②$
可以得到:$ad < bc$
,那么$\frac a b = \frac {ab+ad} {b(b+d)} < \frac {ab+bc} {b(b+d)} = \frac{a+c}{b+d}③$
即① < ③
且:$\frac{a+c}{b+d} = \frac {ad+cd} {d(b+d)} < \frac {bc+cd} {d(b+d)} = \frac c d$
即③ < ②
$\therefore ①<③<② that is \frac a b < \frac {a+c}{b+d} < \frac c d$
字符编码与字节
- 编码系统
字符就是我们看到的”文字“。世界上有很多种语言,比如英语,法语,中文,日语,韩语等等。’abcd’, ‘我’, ‘ả’等等都是字符。字符是人类理解的文字,而计算机则只能理解二进制位(010101…),8个二进制位为一个字节(byte)。要将人类理解的字符转换成计算机理解的字节,就需要编码(encode)。英语世界里有一个著名的编码系统ASCII,使用一个字节来编码字符。ASCII码一共规定了128个字符的编码,比如空格”SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。但是在非英语语系中,像中文,日语和韩语等语言,一个字节并不能编码所有的字符,这时ASCII编码就不适用了。
不同的国家就创造了自己的编码系统。比如简体中文的GB2312,繁体中文的big5,俄语用koi8-r等。但是不同的编码系统会造成混乱,比如130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג)。所以如果两个人在交换文件时用的编码却不同就会出现所谓的”乱码“。
这个时候,UNICODE出现了。当当当,救星出世!
Unicode编码系统为表达任意语言的任意字符而设计。它使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph)。每个数字代表 唯一 的至少在某种语言中使用的符号。这样一来,每个字符对应一个数字,每个数字对应一个字符。即不存在二义性。不再需要记录“模式”了。U+0041总是代表’A’,即使这种语言没有’A’这个字符。
http://unicode-table.com/可以查看所有字符的Unicode码。
Unicode又有几种实现形式:
- UCS-4(UTF-32) 使用4字节编码
- UCS-2(UTF-16) 使用2字节编码
- UTF-8 使用1-4字节编码
其中以UTF-8最流行。
UTF-8是一种为Unicode设计的变长(variable-length)编码系统。即,不同的字符可使用不同数量的字节编码。对于ascii字符(A-Z, &c.)utf-8仅使用1个字节来编码。事实上,utf-8中前128个字符(0–127)使用的是跟ascii一样的编码方式。像ñ和ö这样的“扩展拉丁字符(Extended Latin)”则使用2个字节来编码。中文字符比如“中”则占用了3个字节。很少使用的“星芒层字符”则占用4个字节。
这样既可以照顾到所有的字符又能节约存储空间,如果所有的计算机都使用UTF-8编码的话那就“沟通零距离”了。
- Python中的字符与字节
在Python 3中,所有的字符串都是使用Unicode编码的字符序列。utf-8是一种将字符编码成字节序列的方式。编码字符可以使用str.encode()
,而解码则使用bytes.decode()
1 | # 将'我'编码成字节序列(bytes),使用utf-8 |
- String vs. Bytes
字节即字节;字符是一种抽象。一个不可变(immutable)的Unicode编码的字符序列叫做string。一串由 0到255 之间的数字组成的序列叫做bytes对象。
1 | # 使用“byte字面值”语法b''来定义bytes对象。byte字面值里的每个字节可以是ascii字符或者是从\x00到\xff编码了的16进制数。 |
参考:http://sebug.net/paper/books/dive-into-python3/strings.html
二叉堆简单实现
- 二叉堆的定义
二叉堆是一棵完全二叉树。二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆。
当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆。 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆。
这里我们实现 最小二叉堆堆 。
- 二叉堆的基本操作
下图是一个最小二叉堆,使用数组形式表示:数组索引从1开始。
- 插入新元素
比如插入7
,首先将7
加在数组的末尾,然后与其父节点比较,如果小于父节点则与之交换,直到大于父节点或到达树的根部。
- 删除最小元素
首先移除根部的元素。然后将最后一个元素移到根部,再向下过滤,遇到比它小的元素则交换,直到到达叶子节点或者没有比它更小的元素。
- 二叉堆实现
1 |
|
DOM与jQuery对象互换
我们知道,DOM对象只能使用原生JS的方法,而jQuery对象只能使用jQuery的方法。如果要在原生JS里使用jQuery对象或者对DOM对象使用jQuery方法的话就必须将二者进行转换。
- DOM对象转为jQuery对象
只需要将DOM对象用$()
进行包装:$(DOMObj)
- jQuery对象转为DOM对象
jQuery中介绍了一个get(index)
的方法
> Retrieve the DOM elements matched by the jQuery object.
当然也可以使用数组形式的访问,如$("#selector")[0]
简单吧^_^