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];
    }
View Code

注意:上楼梯的方式总数很快就会突破整数(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;
    }
View Code

解法二:充分利用数组有序这个条件,比较中间元素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);
    }
View Code

进阶:如果数组元素有重复值,又该如何处理?

思路:先比较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);
    }
View Code

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);
    }
View Code

注意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))两种方式