airbnb面试题汇总
https://github.com/gabhi/leetcode-1/blob/master/b/HilbertCurve.java
public static int[][] generateHC(int n) {
int width = (int) Math.pow(2, n);
int[][] res = new int[width][width];
res[0][0] = 1;
res[0][1] = 2;
res[1][0] = 0;
res[1][1] = 3;
if(n <= 1) return res;
int w = 2;
for(int i = 2; i <= n; i++) {
w *= 2; //4
// top left
copy(res, w, 0, 0, w / 4, w / 4); // [0, 0] -> [1, 1]
// top right
copy(res, 2 * w, 0, w / 2, w / 2 - 1, w - 1); // [0, 2] -> [1, 3]
}
return res;
}
public static void copy(int[][] res, int offset, int x1, int y1, int x2, int y2) {
System.out.println("index: " + x1 + " " + x2 + " " + y1 + " " + y2);
for(int x = x1; x <= x2; x++) {
for(int y = y1; y <= y2; y++) {
// System.out.println(x + " " + y);
res[x][y] = res[x][y] + offset;
}
}
}
public static void main(String[] args) {
int n = 2;
int[][] result = generateHC(n);
for(int[] row : result) {
for(int elem : row) {
System.out.print(elem + " ");
}
System.out.println();
}
}
http://www.cnblogs.com/xuyuan77/archive/2008/10/13/1310269.html
Hilbert Curve
Hilbert曲线可以无限阶下去,从1阶开始,落在一个矩阵里,让你写个function,三个参数(x,y,阶数),return 这个点(x,y)是在这阶curve里从原点出发的第几步
Hilbert曲线可以无限阶下去,从1阶开始,落在一个矩阵里,让你写个function,三个参数(x,y,阶数),return 这个点(x,y)是在这阶curve里从原点出发的第几步
int hilbertCurve(int x, int y, int iter) {
if (iter == 0) return 1;
int areaCnt = (1 << (iter * 2 - 2)); // 每一块区域边长的边界值
int borderLen = (1 << (iter - 1)); // 区域移动的长度
if (x >= borderLen && y >= borderLen) //右上角区域 = 前一阶往右上角移动borderLen
return areaCnt * 2 + hilbertCurve(x - borderLen, y - borderLen, iter - 1);
else if (x < borderLen && y >= borderLen) //左上角区域 = 前一阶往上移动borderLen
return areaCnt + hilbertCurve(x, y - borderLen, iter - 1);
else if (x < borderLen && y < borderLen) //右下角区域 = 前一阶按照y=x对称
return hilbertCurve(y, x, iter - 1);
else //右下角区域 = 前一阶按照y=-x对称,然后右移2*borderLen - 1,上移borderLen - 1
// 设原来坐标(a,b) => (-b, -a) => (2*borderLen - 1 - b, borderLen - 1 - a) = (x, y)
// => a = borderLen - 1 - y, b = 2*borderLen - 1 - x
return areaCnt * 3 + hilbertCurve(borderLen - 1 - y, 2 * borderLen - 1 - x, iter - 1);
}
https://github.com/allaboutjst/airbnb/blob/master/src/main/java/hilbert_curve/HilbertCurve.java public int hilbertCurve(int x, int y, int iter) {
if (iter == 0) return 1;
int len = 1 << (iter - 1);
int num = 1 << (2 * (iter - 1));
if (x >= len && y >= len) {
// 3 Shape is identical with previous iteration
return 2 * num + hilbertCurve(x - len, y - len, iter - 1);
} else if (x < len && y >= len) {
// 2 Shape is identical with previous iteration
return num + hilbertCurve(x, y - len, iter - 1);
} else if (x < len && y < len) {
// 1 Clock-wise rotate 90
return hilbertCurve(y, x, iter - 1);
} else {
// 4 Anti-Clockwise rotate 90
return 3 * num + hilbertCurve(len - y - 1, 2 * len - x - 1, iter - 1);
}
}
}
public static int[][] generateHC(int n) {
int width = (int) Math.pow(2, n);
int[][] res = new int[width][width];
res[0][0] = 1;
res[0][1] = 2;
res[1][0] = 0;
res[1][1] = 3;
if(n <= 1) return res;
int w = 2;
for(int i = 2; i <= n; i++) {
w *= 2; //4
// top left
copy(res, w, 0, 0, w / 4, w / 4); // [0, 0] -> [1, 1]
// top right
copy(res, 2 * w, 0, w / 2, w / 2 - 1, w - 1); // [0, 2] -> [1, 3]
}
return res;
}
public static void copy(int[][] res, int offset, int x1, int y1, int x2, int y2) {
System.out.println("index: " + x1 + " " + x2 + " " + y1 + " " + y2);
for(int x = x1; x <= x2; x++) {
for(int y = y1; y <= y2; y++) {
// System.out.println(x + " " + y);
res[x][y] = res[x][y] + offset;
}
}
}
public static void main(String[] args) {
int n = 2;
int[][] result = generateHC(n);
for(int[] row : result) {
for(int elem : row) {
System.out.print(elem + " ");
}
System.out.println();
}
}
http://www.cnblogs.com/xuyuan77/archive/2008/10/13/1310269.html
德国数学家David Hilbert发现了一种曲线,首先把一个正方形等分成四个小正方形,依次从西南角的正方形中心出发往北到西北正方形中心,再往东到东北角的正方形中心,再往南到东南角正方形中心,这是一次迭代,如果对四个小正方形继续上述过程,往下划分,反复进行,最终就得到一条可以填满整个正方形的曲线,这就是Hibert曲线,其大致过程如下图所示
Hibert曲线生成过程
下面我们来看如何写程序生成这样的曲线,其实不管迭代多少次,都是由如下的图形
基本图
构成,唯一所不同的是开口方向不一样。开口方向不一样就涉及到图像旋转,图像旋转的基本知识接下来会介绍。目前我们最关心的是这样生成的曲线过程右什么规律,从上述描述生成的过程就已经看出了规律,当然人肯定一眼就看出来了,但计算机如何知道呢?这就是生成Hibert曲线算法的关键了:
为了便于找出规律,我们来看下面一副图
上图中应该是把所有开口方向(共四种)都涵盖了。我们约定四种类型:
开口往南-0,开口往西-1,开口往北-2,开口往东-3。我们结合基本图,就有这样的规律,画表如下:
点
|
点所在图类型
|
以该点为中心产生的图类型
|
dot1
|
0
|
1
|
dot1
|
1
|
2
|
dot1
|
2
|
3
|
dot1
|
3
|
0
|
其他的点类似也有类似的规律,这个规律才是我们编码的基础。是下次递归调用画图函数传参数的前提。下面我们来看一下画图中涉及到的图像旋转的相关数学知识。
图像旋转
图像旋转是指把定义的图像绕某一点以逆时针或顺时针方向旋转一定的角度,通常是指绕图像的中心以逆时针方向旋转。
假设图像的左上角为(left, top),右下角为(right, bottom),则图像上任意点(x0, y0)绕其中心(xcenter, ycenter)逆时针旋转angle角度后,新的坐标位置(x′, y′)的计算公式为:
xcenter = (right - left + 1) / 2 + left;
ycenter = (bottom - top + 1) / 2 + top;
x′ = (x0 - xcenter) cosθ - (y0 - ycenter) sinθ + xcenter;
y′ = (x0 - xcenter) sinθ + (y0 - ycenter) cosθ + ycenter;
与图像的镜像变换相类似,也采用按行逐点变换的方式实现图像的旋转。
由于它能填满平面,它的豪斯多夫维是2。取它填充的正方形的边长为1,第n步的希尔伯特曲线的长度是2n - 2-n。