May
16
早上参加了腾讯的笔试,做完以后自我感觉良好,但是后来和sandy讨论了一下,发现还是挫了,因为没用上Hash。
于是中午回去狠查了一些资料,看到了一点东西,充实了些。
看到一些字符串的Hash函数,想测试一下它们的实际性能
于是写了个程序来生成5w个字符串
用不同的hash函数计算hash值模9793(随便写的一个数字)
然后再用 sort 和 uniq 看了一下结果,发现 sdbmhash 是最好的, jshash其次,也很不错
然而很意外的是 elfhash 的性能则相当差,完全达不到可用的标准
——在对5w个数进行hash以后得到的结果里面,居然有700多个0和400多个1。
下面贴一些代码:
gen_data.cpp
hash.cpp
查看结果:
于是中午回去狠查了一些资料,看到了一点东西,充实了些。
下载文件 (已下载 1798 次)
看到一些字符串的Hash函数,想测试一下它们的实际性能
于是写了个程序来生成5w个字符串
用不同的hash函数计算hash值模9793(随便写的一个数字)
然后再用 sort 和 uniq 看了一下结果,发现 sdbmhash 是最好的, jshash其次,也很不错
然而很意外的是 elfhash 的性能则相当差,完全达不到可用的标准
——在对5w个数进行hash以后得到的结果里面,居然有700多个0和400多个1。
下面贴一些代码:
gen_data.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char tbl[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+=-?><:';,./][{}\\\"";
int main(){
char s[1024];
int i, l, m = strlen(tbl), j;
srand(732984);
freopen("str.txt", "w", stdout);
for (i = 0; i < 50000; ++i){
l = rand() % 100 + 1;
for (j = 0; j < l; ++j)
s[j] = tbl[rand() % m];
s[j] = 0;
printf("%s\n", s);
}
return 0;
}
#include <stdlib.h>
#include <string.h>
char tbl[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+=-?><:';,./][{}\\\"";
int main(){
char s[1024];
int i, l, m = strlen(tbl), j;
srand(732984);
freopen("str.txt", "w", stdout);
for (i = 0; i < 50000; ++i){
l = rand() % 100 + 1;
for (j = 0; j < l; ++j)
s[j] = tbl[rand() % m];
s[j] = 0;
printf("%s\n", s);
}
return 0;
}
hash.cpp
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
unsigned int elfhash(char *s){
int hash = 0, x = 0;
while (*s){
hash = (hash << 4) + (*s++);
if(((x = hash) & 0xf0000000l) != 0){
hash ^= (x >> 24);
hash &= x;
}
}
return hash & 0x7fffffffl;
}
unsigned int jshash(char *s){
int hash = 1315423911;
while (*s){
hash ^= (hash << 5) + *s++ + (hash >> 2);
}
return (hash & 0x7fffffffl);
}
unsigned int sdbmhash(char *s){
int hash = 0;
while (*s){
hash = (hash << 6) + (hash << 16) - hash + *s++;
}
return (hash & 0x7fffffffl);
}
int main(){
char s[1024];
freopen("str.txt", "r", stdin);
freopen("elf1.txt", "w", stdout);
while(true){
scanf("%s", s);
if(feof(stdin)) break;
printf("%d\n", elfhash(s) % 9793);
}
return 0;
}
#include <cstdlib>
#include <cstring>
using namespace std;
unsigned int elfhash(char *s){
int hash = 0, x = 0;
while (*s){
hash = (hash << 4) + (*s++);
if(((x = hash) & 0xf0000000l) != 0){
hash ^= (x >> 24);
hash &= x;
}
}
return hash & 0x7fffffffl;
}
unsigned int jshash(char *s){
int hash = 1315423911;
while (*s){
hash ^= (hash << 5) + *s++ + (hash >> 2);
}
return (hash & 0x7fffffffl);
}
unsigned int sdbmhash(char *s){
int hash = 0;
while (*s){
hash = (hash << 6) + (hash << 16) - hash + *s++;
}
return (hash & 0x7fffffffl);
}
int main(){
char s[1024];
freopen("str.txt", "r", stdin);
freopen("elf1.txt", "w", stdout);
while(true){
scanf("%s", s);
if(feof(stdin)) break;
printf("%d\n", elfhash(s) % 9793);
}
return 0;
}
查看结果:
引用
$ sort elf1.txt | less
$ sort elf1.txt | uniq | less
$ sort elf1.txt | uniq | less
May
16
把手头另外一个移动的号码开通了fetion
然后加上昨天发现的那个php的fetion处理了一下
现在大家可以在线免费给我发短信拉!
想自己架设一个?下载这个东西去玩儿吧:
然后加上昨天发现的那个php的fetion处理了一下
现在大家可以在线免费给我发短信拉!
想自己架设一个?下载这个东西去玩儿吧:
下载文件 (已下载 1738 次)
May
16
(参考网上的资料)用到了 ImageMagick 工具包。
@ Ubuntu
sudo apt-get install imagemagick
就可以把 1.jpg 的尺寸缩小到越来的1/4
就可以把 1.jpg 的尺寸缩小到400x300
注意,两个比率/数字之间的是字母x,不是乘号。
然后来个批量转换的东东(网上的教程是for,虽然我比较喜欢find)
如果要递归地转换当前目录以及子目录的图像就用find吧:
@ Ubuntu
sudo apt-get install imagemagick
引用
$ convert -resize 50%x50% 1.jpg 1_small.jpg
引用
$ convert -sample 400x300 1.jpg 1_small.jpg
注意,两个比率/数字之间的是字母x,不是乘号。
然后来个批量转换的东东(网上的教程是for,虽然我比较喜欢find)
引用
for img in `ls *.jpg`; do convert -resize 50%x50% $img small_$img; done
如果要递归地转换当前目录以及子目录的图像就用find吧:
引用
find -name "*.jpg" -exec convert -resize 50%x50% {} {}.small.jpg
May
15
这下方便了。。可以直接从网页上发短信了。。。
网上有现成的,比较常见的是 http://sms.api.bz ,应该是安全的,不过毕竟是别人搭建的,不放心。
如果自己搭建,可以用这个:
不过要求是安装了php5-curl模块的。
网上有现成的,比较常见的是 http://sms.api.bz ,应该是安全的,不过毕竟是别人搭建的,不放心。
如果自己搭建,可以用这个:
下载文件 (已下载 1738 次)
不过要求是安装了php5-curl模块的。
May
15
不知道从什么时候开始,发现当使用phpmailer发送邮件的时候
如果邮件标题长度超过16个字符,无论调整成什么编码,收到的邮件都是乱码。
昨天发现了别人的应用,却发现非常正常。
对比之下,发现原来我用的是phpmailer v2.3,别人用的是v2.0
降级成旧版本以后发现一切都正常了。。。Orz
原来是新版本的Bug,郁闷了我好久。。。。
于是把所有用到phpmailer的应用都替换了一下。。。
如果邮件标题长度超过16个字符,无论调整成什么编码,收到的邮件都是乱码。
昨天发现了别人的应用,却发现非常正常。
对比之下,发现原来我用的是phpmailer v2.3,别人用的是v2.0
降级成旧版本以后发现一切都正常了。。。Orz
原来是新版本的Bug,郁闷了我好久。。。。
于是把所有用到phpmailer的应用都替换了一下。。。
May
13
预计覆盖以下内容:
1。安装基本知识
2。添加源(教育网and电信)
3。完整的中文语言支持(输入法)
4。apt-get基本知识
5。root用户相关
6。nVidia显卡驱动
7。引导相关(Grub,Windows,修复,单用户模式)
8。多媒体相关
9。常用软件推荐
另,发现一篇更全的东西:速配指南
http://wiki.ubuntu.org.cn/index.php?title=%E9%80%9F%E9%85%8D%E6%8C%87%E5%8D%97&variant=zh-cn
-----华丽的分割线-----
1。安装基本知识
2。添加源(教育网and电信)
3。完整的中文语言支持(输入法)
4。apt-get基本知识
5。root用户相关
6。nVidia显卡驱动
7。引导相关(Grub,Windows,修复,单用户模式)
8。多媒体相关
9。常用软件推荐
另,发现一篇更全的东西:速配指南
http://wiki.ubuntu.org.cn/index.php?title=%E9%80%9F%E9%85%8D%E6%8C%87%E5%8D%97&variant=zh-cn
-----华丽的分割线-----
May
13
今天回顾WOJ1398,发现了这个当时没有理解透彻的算法。
看了好久好久,现在终于想明白了。
试着把它写下来,让自己更明白。
最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS。
排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了。
假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。
下面一步一步试着找出它。
我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了
首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1
然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1
接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1..2] = 1, 5,Len=2
再来,d[4] = 3,它正好加在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时候B[1..2] = 1, 3,Len = 2
继续,d[5] = 6,它在3后面,因为B[2] = 3, 而6在3后面,于是很容易可以推知B[3] = 6, 这时B[1..3] = 1, 3, 6,还是很容易理解吧? Len = 3 了噢。
第6个, d[6] = 4,你看它在3和6之间,于是我们就可以把6替换掉,得到B[3] = 4。B[1..3] = 1, 3, 4, Len继续等于3
第7个, d[7] = 8,它很大,比4大,嗯。于是B[4] = 8。Len变成4了
第8个, d[8] = 9,得到B[5] = 9,嗯。Len继续增大,到5了。
最后一个, d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。
于是我们知道了LIS的长度为5。
!!!!! 注意。这个1,3,4,7,9不是LIS,它只是存储的对应长度LIS的最小末尾。有了这个末尾,我们就可以一个一个地插入数据。虽然最后一个d[9] = 7更新进去对于这组数据没有什么意义,但是如果后面再出现两个数字 8 和 9,那么就可以把8更新到d[5], 9更新到d[6],得出LIS的长度为6。
然后应该发现一件事情了:在B中插入数据是有序的,而且是进行替换而不需要挪动——也就是说,我们可以使用二分查找,将每一个数字的插入时间优化到O(logN)~~~~~于是算法的时间复杂度就降低到了O(NlogN)~!
代码如下:
update @ 2016-08-21
没想到7年多了还要更新一下……
有几位同学在评论中问到如何给出一个LIS而不仅是计算长度。具体的代码我没有写过,不过大概可以这么实现:更新B[i]的时候,把记下来数字在原来数组中的下标也记下来(被替换的数据保留在一个后备数组中)。等到得出 B[n] 了以后,用贪心算法往前回溯,每次找出B[i-1]对应后备数组中值小于B[i]、下标小于B[i]下标、且在该后备数组中下标最大的那个。
update @ 2017-04-16
补充一下,由于上面那段代码用的是upper_bound,所以实际上求的是最长不下降子序列;如果要求递增子序列,应该改用lower_bound。
看了好久好久,现在终于想明白了。
试着把它写下来,让自己更明白。
最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS。
排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了。
假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。
下面一步一步试着找出它。
我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了
首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1
然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1
接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1..2] = 1, 5,Len=2
再来,d[4] = 3,它正好加在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时候B[1..2] = 1, 3,Len = 2
继续,d[5] = 6,它在3后面,因为B[2] = 3, 而6在3后面,于是很容易可以推知B[3] = 6, 这时B[1..3] = 1, 3, 6,还是很容易理解吧? Len = 3 了噢。
第6个, d[6] = 4,你看它在3和6之间,于是我们就可以把6替换掉,得到B[3] = 4。B[1..3] = 1, 3, 4, Len继续等于3
第7个, d[7] = 8,它很大,比4大,嗯。于是B[4] = 8。Len变成4了
第8个, d[8] = 9,得到B[5] = 9,嗯。Len继续增大,到5了。
最后一个, d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。
于是我们知道了LIS的长度为5。
!!!!! 注意。这个1,3,4,7,9不是LIS,它只是存储的对应长度LIS的最小末尾。有了这个末尾,我们就可以一个一个地插入数据。虽然最后一个d[9] = 7更新进去对于这组数据没有什么意义,但是如果后面再出现两个数字 8 和 9,那么就可以把8更新到d[5], 9更新到d[6],得出LIS的长度为6。
然后应该发现一件事情了:在B中插入数据是有序的,而且是进行替换而不需要挪动——也就是说,我们可以使用二分查找,将每一个数字的插入时间优化到O(logN)~~~~~于是算法的时间复杂度就降低到了O(NlogN)~!
代码如下:
//在非递减序列 arr[s..e](闭区间)上二分查找第一个大于等于key的位置,如果都小于key,就返回e+1
int upper_bound(int arr[], int s, int e, int key)
{
int mid;
if (arr[e] <= key)
return e + 1;
while (s < e)
{
mid = s + (e - s) / 2;
if (arr[mid] <= key)
s = mid + 1;
else
e = mid;
}
return s;
}
int LIS(int d[], int n)
{
int i = 0, len = 1, *end = (int *)alloca(sizeof(int) * (n + 1));
end[1] = d[0]; //初始化:长度为1的LIS末尾为d[0]
for (i = 1; i < n; i++)
{
int pos = upper_bound(end, 1, len, d[i]); //找到插入位置
end[pos] = d[i];
if (len < pos) //按需要更新LIS长度
len = pos;
}
return len;
}
int upper_bound(int arr[], int s, int e, int key)
{
int mid;
if (arr[e] <= key)
return e + 1;
while (s < e)
{
mid = s + (e - s) / 2;
if (arr[mid] <= key)
s = mid + 1;
else
e = mid;
}
return s;
}
int LIS(int d[], int n)
{
int i = 0, len = 1, *end = (int *)alloca(sizeof(int) * (n + 1));
end[1] = d[0]; //初始化:长度为1的LIS末尾为d[0]
for (i = 1; i < n; i++)
{
int pos = upper_bound(end, 1, len, d[i]); //找到插入位置
end[pos] = d[i];
if (len < pos) //按需要更新LIS长度
len = pos;
}
return len;
}
update @ 2016-08-21
没想到7年多了还要更新一下……
有几位同学在评论中问到如何给出一个LIS而不仅是计算长度。具体的代码我没有写过,不过大概可以这么实现:更新B[i]的时候,把记下来数字在原来数组中的下标也记下来(被替换的数据保留在一个后备数组中)。等到得出 B[n] 了以后,用贪心算法往前回溯,每次找出B[i-1]对应后备数组中值小于B[i]、下标小于B[i]下标、且在该后备数组中下标最大的那个。
update @ 2017-04-16
补充一下,由于上面那段代码用的是upper_bound,所以实际上求的是最长不下降子序列;如果要求递增子序列,应该改用lower_bound。
May
12
张文给的模板,很赞~对中文的支持比CJK好得不是一点阿。。。用这个写了自己的简历,很爽~
$ xelatex a.tex
$ xelatex a.tex
$ evince a.pdf
$ xelatex a.tex
$ xelatex a.tex
$ evince a.pdf
\documentclass[a4paper]{article}
\usepackage{hyperref}%不能有unicode选项,否则bookmark会是乱码
\usepackage{fontspec}
\setromanfont{WenQuanYi Zen Hei}%字体
%中文断行
\XeTeXlinebreaklocale "zh"
\XeTeXlinebreakskip = 0pt plus 1pt
\hypersetup{pdfauthor={},
pdftitle={}} %注意,在document之外的导言区
\title{}
\author{张文}
\begin{document}
\renewcommand{\today}{\number\year 年\number\month 月\number\day 日}
\maketitle
\pagenumbering{Roman}
\newpage
\renewcommand{\contentsname}{\centerline{目\quad 录}}
\tableofcontents
\newpage
\pagenumbering{arabic}
\section{}
\newpage
\renewcommand{\refname}{参考文献}
\begin{thebibliography}{99}
\bibitem{Chisnall} D. Chisnall. 2007. \textsl{The Definitive Guide to the Xen Hypervisor.}
\end{thebibliography}
\end{document}
\usepackage{hyperref}%不能有unicode选项,否则bookmark会是乱码
\usepackage{fontspec}
\setromanfont{WenQuanYi Zen Hei}%字体
%中文断行
\XeTeXlinebreaklocale "zh"
\XeTeXlinebreakskip = 0pt plus 1pt
\hypersetup{pdfauthor={},
pdftitle={}} %注意,在document之外的导言区
\title{}
\author{张文}
\begin{document}
\renewcommand{\today}{\number\year 年\number\month 月\number\day 日}
\maketitle
\pagenumbering{Roman}
\newpage
\renewcommand{\contentsname}{\centerline{目\quad 录}}
\tableofcontents
\newpage
\pagenumbering{arabic}
\section{}
\newpage
\renewcommand{\refname}{参考文献}
\begin{thebibliography}{99}
\bibitem{Chisnall} D. Chisnall. 2007. \textsl{The Definitive Guide to the Xen Hypervisor.}
\end{thebibliography}
\end{document}