剑指offer题解12-16

剑指offer题解

12 矩阵中的路径

1571393951935

public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
    if (matrix == null || str == null || rows <= 0 || cols <= 0) {
        return false;
    }

    //标记数组,用来记录该字符是否访问过
    boolean[][] mark = new boolean[rows][cols];
    char[][] chars = toArray(matrix, rows, cols);

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (process(chars, str, 0, mark, i, j)) {
                return true;
            }
        }
    }

    return false;
}

//将一维数组转换成二维数组
public char[][] toArray(char[] matrix, int rows, int cols) {
    char[][] chars = new char[rows][cols];
    for (int i = 0, index = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            chars[i][j] = matrix[index++];
        }

    }
    return chars;
}

//递归函数
public boolean process(char[][] chars, char[] str, int pathLength, boolean[][] mark, int row, int column) {
    //遍历的路径长度和字符串长度相等,说明,之前的字符都已经成功匹配,返回true
    if (pathLength == str.length) {
        return true;
    }
    //数组下标越界、字符不匹配、字符已经访问过,都返回false
    if (row < 0 || column < 0 || row >= chars.length || column >= chars[0].length
        || chars[row][column] != str[pathLength] || mark[row][column]) {
        return false;
    }
    //字符已访问,标记为true
    mark[row][column] = true;
    //递归遍历该字符傍边的字符,匹配成功,则路径长度加1
    if (process(chars, str, pathLength + 1, mark, row - 1, column) ||
        process(chars, str, pathLength + 1, mark, row + 1, column) ||
        process(chars, str, pathLength + 1, mark, row, column - 1) ||
        process(chars, str, pathLength + 1, mark, row, column + 1)) {
        return true;
    }
    //该字符旁边的字符都不匹配,则说明这条路不符合,还原,将字符的遍历标记设置为false
    mark[row][column] = false;
    return false;
}

13 机器人的运动范围

1571394884126

public int movingCount(int threshold, int rows, int cols) {
    //标记数组
    boolean[][] mark = new boolean[rows][cols];
    //存储每个位置的数位和
    int[][] matrix = new int[rows][cols];
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = getValue(i) + getValue(j);
        }
    }

    return process(threshold, matrix, mark, 0, 0, rows, cols);

}

private int process(int threshold, int[][] matrix, boolean[][] mark, int i, int j, int rows, int cols) {
    int count = 0;
    //递归终止条件
    if (i < 0 || j < 0 || i >= rows || j >= cols || matrix[i][j] > threshold || mark[i][j]) {
        return 0;
    }
    //将访问过的位置标记为true
    mark[i][j] = true;
    //访问当前位置,加1,然后继续遍历该位置傍边的位置,累加起来,最终的返回值就是所能到达的格子数
    count = 1 + process(threshold, matrix, mark, i - 1, j, rows, cols) + process(threshold, matrix, mark, i + 1, j, rows, cols) +
        process(threshold, matrix, mark, i, j - 1, rows, cols) + process(threshold, matrix, mark, i, j + 1, rows, cols);
    return count;

}

//计算一个整数的数位之和
public int getValue(int num) {
    int res = 0;
    int tmp = 0;
    while (num / 10 > 0) {
        tmp = num / 10;
        res += num - tmp * 10;
        num = tmp;
    }
    res += num;
    return res;

}

14 剪绳子

1571404008081

    //动态规划,时间复杂度O(n^2),由递归转化而来
    public int cutRopeDP(int target) {
        if (target < 2) {
            return 0;
        }
        if (target == 2) {
            return 1;
        }
        if (target == 3) {
            return 2;
        }
        int[] dp = new int[target + 1];
        dp[1] = 1;
        dp[2] = 2;
        dp[3] = 3;
        for (int i = 4; i <= target; i++) {
            for (int j = 1; j <= i / 2; j++) {

                dp[i] = Math.max(dp[i], dp[j] * dp[i - j]);
            }
        }
        return dp[target];

    }

    //    贪心,时间复杂度O(1)
    //    n>4时,划分出尽可能多的3,因为3(n-3)>=2(n-2)
    //    n=4时,2*2 > 3*1,所以当划分出1和3时,要转变成2和2
    //    n<4时,特殊情况,单独处理
    public int cutRopeGreedy(int target) {
        if (target < 2) {
            return 0;
        }
        if (target == 2) {
            return 1;
        }
        if (target == 3) {
            return 2;
        }
        int timeOf3 = target / 3;
        if (target - timeOf3 * 3 == 1) {
            timeOf3--;
        }

        int timeOf2 = (target - timeOf3 * 3) / 2;
        int res = (int) (Math.pow(3, timeOf3) * Math.pow(2, timeOf2));
        return res;

    }

15 二进制中1的个数

1571829733900

public int NumberOf1(int n) {
        //数字在计算机中以二进制形式存储,负数在计算机中以补码存储,int类型的数据占4个字节
        //为了防止负数右移出现死循环的情况,可以把1每次左移一位,然后和n比较
        int res = 0;
        int flag = 1;
        while (flag != 0) {
            if ((n & flag) != 0) {
                res++;
            }
            flag = flag << 1;
        }
        return res;
    }

    public int NumberOf1Improve(int n) {
        //(n-1)&n 每次运算的结果将n中二进制表示最右边的1变为0
        int res = 0;
        while (n != 0) {
            n=(n-1)&n;
            res++;
        }
        return res;
    }

16 数值的整数次方

1571831242479

  • base=0,exponent<0是非法输入,给用户提示输入错误
  • 提高运算效率:
  • 1571831788488
public class NumberExponent_16 {
    public double Power(double base, int exponent) {
        //非法输入
        if (base == 0 && exponent < 0) {
            throw new RuntimeException("input number error!");
        }
        double res = 1;
        double tmp = exponent;
        if (exponent < 0) {
            exponent = -exponent;
        }
        //O(n)
        for (int i = 1; i <= exponent; i++) {
            res = res * base;
        }
        if (tmp < 0) {
            res = 1 / res;
        }

        return res;

    }

    public double PowerImprove(double base, int exponent) {
        //非法输入
        if (base == 0 && exponent < 0) {
            throw new RuntimeException("input number error!");
        }
        double res = 1;
        double tmp = exponent;
        if (exponent < 0) {
            exponent = -exponent;
        }

        if (exponent % 2 == 0) {
            //O(n/2)
            for (int i = 1; i <= exponent / 2; i++) {
                res = res * base;
            }
            res = res * res;
        } else {
            for (int i = 1; i <= (exponent - 1) / 2; i++) {
                res = res * base;
            }
            res = res * res * base;
        }

        if (tmp < 0) {
            res = 1 / res;
        }

        return res;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值