1.有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一个方法,计算小孩有多少种上楼梯的方式。
思路:采用自上而下的方式解决问题。最后一步可能是从第n-1阶往上走1阶、从第n-2阶往上走2阶、或从第n-3阶往上走3阶。因此,抵达最后一阶的走法,就是抵达这最后三阶的方式的总和。
public static int climbStairs(int n) { // Write your code here if (n <= 1){ return 1; } long[] f = new long[n + 1]; f[0] = 1; f[1] = 1; f[2] = 2; for (int i = 3; i < n + 1; i++) { f[i] = f[i - 1] + f[i - 2] + f[i - 3]; f[i] = f[i] % 1000000007; } return (int)f[n]; }
注意:上楼梯的方式总数很快就会突破整数(int型)的上限而溢出。当n=37时,结果就会溢出。所以使用long型,并且一直%1000000007。
2.设想有个机器人坐在X*Y网格的左上角,只能向右、向下移动。机器人从(0,0)到(X,Y)有多少种走法?
进阶:假设有些点为“禁区”,机器人不能踏足。设计一种算法,找出一条路径,让机器人从左上角移动到右下角。
解法:《九章算法》chapter nine unique-pathsI II
3.在数组A[0...n-1]中,有所谓的魔术索引,满足条件A[i]=i。给定一个有序整数数组,元素值各不相同,编写一个方法,在数组A中找出魔术索引,若存在的话。
解法一:蛮力法
public boolean findMagicIndex(int[] A, int n){ for(int i = 0; i < A.length; i++){ if(i == A[i]) { return true; } } return false; }
解法二:充分利用数组有序这个条件,比较中间元素A[mid]和其位置mid,若A[mid]<mid,则魔术索引一定在数组右侧。
public static int magicFast(int[] array, int start, int end) { if (end < start || start < 0 || end >= array.length) { return -1; } int mid = (start + end) / 2; if (array[mid] == mid) { return mid; } else if (array[mid] < mid) { return magicFast(array, mid + 1, end); } else { return magicFast(array, start, mid - 1); } } public static int magicFast(int[] array) { return magicFast(array, 0, array.length - 1); }
进阶:如果数组元素有重复值,又该如何处理?
思路:先比较midIndex和midValue是否相同。若两者不同,则按如下方式递归搜索左半部分和右半部分。
左半部分:搜索索引从start到Math.min(midIndex-1, midValue)的元素。
右半部分:搜索索引从Math.max(midIndex+1, midValue)到end的元素。
public static int magicFast(int[] array, int start, int end) { if (end < start || start < 0 || end >= array.length) { return -1; } int midIndex = (start + end) / 2; int midValue = array[midIndex]; if (midValue == midIndex) { return midIndex; //搜索左半部分 } int leftIndex = Math.min(midIndex - 1, midValue); int left = magicFast(array, start, leftIndex); if (left >= 0) { return left; } //搜索右半部分 int rightIndex = Math.max(midIndex + 1, midValue); int right = magicFast(array, rightIndex, end); return right; } public static int magicFast(int[] array) { return magicFast(array, 0, array.length - 1); }
4.编写一个方法,返回某集合的所有子集。
5.编写一个方法,确定某字符串的所有排列组合。
6.实现一种算法,打印n对括号的全部有效组合(即左右括号正确配对)。
示例:输入:3 输出:((())),(()()),(())(),()(()),()()()
7.编写函数,实现许多图片编辑软件都支持的“颜色填充”功能。给定一个屏幕(以二维数组表示,元素为颜色值)、一个点和一个新的颜色值,将新颜色值填入这个点的周围区域,直到原来的颜色值全都改变。
思路:假设要对一个像素(比如绿色)调用paintFill(也即点击图片编辑软件的填充颜色),我们希望颜色向四周"渗出“。我们会对周围的像素逐一调用paintFill,向外扩张,一旦碰到非绿色的像素就停止填充。
public enum Color { Black, White, Red, Yellow, Green } public static boolean paintFill(Color[][] screen, int x, int y, Color ocolor, Color ncolor) { if (x < 0 || x >= screen[0].length || y < 0 || y >= screen.length) { return false; } if (screen[y][x] == ocolor) { screen[y][x] = ncolor; paintFill(screen, x - 1, y, ocolor, ncolor); paintFill(screen, x + 1, y, ocolor, ncolor); paintFill(screen, x , y - 1, ocolor, ncolor); paintFill(screen, x , y + 1, ocolor, ncolor); } return true; } public static boolean paintFill(Color[][] screen, int x, int y, Color ncolor) { if (screen[y][x] == ncolor) { return false; } return paintFill(screen, x, y, screen[y][x], ncolor); }
注意screen[y][x]中x和y的顺序,碰到图像问题时切记这一点。因为x表示水平轴(也即自左向右),实际上对应于列数而非行数。y的值等于行数。
8.给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。
9.设计一种算法,打印八皇后在8*8棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。
10.给你一堆n个箱子,箱子宽wi,高hi,深di。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子。实现一个方法,搭出最高的一堆箱子,箱堆的高度为每个箱子高度的总和。
11.给定一个布尔表达式,由0、1、&、|和^等符号组成,以及一个想要的布尔结果result,实现一个函数,算出有几种括号的放法可使该表达式得出result值。
示例:表达式:1^0|0|1 期望结果:false(0) 输出:1^((0|0)|1)和1^(0|(0|1))两种方式