leetcode刷面试题(面试题08合集)

面试题 08.01. 三步问题

三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

示例1:
输入:n = 3
输出:4
说明: 有四种走法

示例2:
输入:n = 5
输出:13

提示:
n范围在[1, 1000000]之间

public int waysToStep(int n) {
    int MOD = 1000000007;
    long[] ans = new long[n + 3];
    ans[2] = 1;
    for (int i = 3; i < n + 3; i++) {
        ans[i] = (ans[i - 3] + ans[i - 2] + ans[i - 1]) % MOD;
    }
    return (int) ans[n + 2];
}

面试题 08.02. 迷路的机器人

设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。
网格中的障碍物和空位置分别用 1 和 0 来表示。
返回一条可行的路径,路径由经过的网格的行号和列号组成。左上角为 0 行 0 列。

示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: [[0,0],[0,1],[0,2],[1,2],[2,2]]
解释:
输入中标粗的位置即为输出表示的路径,即
0行0列(左上角) -> 0行1列 -> 0行2列 -> 1行2列 -> 2行2列(右下角)

说明:r 和 c 的值均不超过 100。

public List> pathWithObstacles(int[][] obstacleGrid) {
    List> ans = new ArrayList<>();
    int rNum = obstacleGrid.length;
    int cNum = obstacleGrid[0].length;
    boolean[][] check = new boolean[rNum][cNum];
    if (obstacleGrid[rNum - 1][cNum - 1] == 1) {
        return ans;
    }
    check[rNum - 1][cNum - 1] = true;
    for (int i = rNum - 2; i >= 0; i--) {
        if (check[i + 1][cNum - 1] && obstacleGrid[i][cNum - 1] == 0) {
            check[i][cNum - 1] = true;
        }
    }
    for (int i = cNum - 2; i >= 0; i--) {
        if (check[rNum - 1][i + 1] && obstacleGrid[rNum - 1][i] == 0) {
            check[rNum - 1][i] = true;
        }
    }
    for (int i = rNum - 2; i >= 0; i--) {
        for (int j = cNum - 2; j >= 0; j--) {
            if (obstacleGrid[i][j] == 1) {
                continue;
            }
            if (check[i][j + 1] || check[i + 1][j]) {
                check[i][j] = true;
            }
        }
    }
    if (!check[0][0]) {
        return ans;
    }
    int x = 0;
    int y = 0;
    while (x < rNum && y < cNum) {
        ans.add(getList(x, y));
        if (x < rNum - 1 && check[x + 1][y]) {
            x++;
            continue;
        }
        if (y < cNum - 1 && check[x][y + 1]) {
            y++;
            continue;
        }
        if (x == rNum - 1 && y == cNum - 1) {
            return ans;
        }
    }
    return ans;
}

private List getList(int x, int y) {
    List list = new ArrayList<>(2);
    list.add(x);
    list.add(y);
    return list;
}

面试题 08.03. 魔术索引

魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。

示例1:
输入:nums = [0, 2, 3, 4, 5]
输出:0
说明: 0下标的元素为0

示例2:
输入:nums = [1, 1, 1]
输出:1

提示:
nums长度在[1, 1000000]之间

public int findMagicIndex(int[] nums) {
    int len = nums.length;
    int sta = 0;
    for (int i = 0; i < len; i++) {
        if (nums[i] < i) {
            continue;
        }
        if (nums[i] == i) {
            return i;
        }
        sta = nums[i];
    }
    for (int i = sta; i < len; i = nums[i]) {
        if (nums[i] == i) {
            return i;
        }
    }
    return -1;
}

面试题 08.04. 幂集

幂集。编写一种方法,返回某集合的所有子集。集合中不包含重复的元素。
说明:解集不能包含重复的子集。

示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

public List> subsets(int[] nums) {
    List> ans = new ArrayList<>();
    List res = new ArrayList<>();
    addValue(ans, res, nums, nums.length, 0);
    return ans;
}

private void addValue(List> ans, List res, int[] nums, int length, int k) {
    if (length == k) {
        ans.add(res);
        return;
    }
    List res2 = new ArrayList<>(res);
    addValue(ans, res, nums, length, k + 1);
    res2.add(nums[k]);
    addValue(ans, res2, nums, length, k + 1);

}著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。	

面试题 08.05. 递归乘法
递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。

示例1:
输入:A = 1, B = 10
输出:10

示例2:
输入:A = 3, B = 4
输出:12

提示:
保证乘法范围不会溢出

public int multiply(int A, int B) {
    if (A > B) {
        return getAns(B, A, 0);
    }
    return getAns(A, B, 0);
}

private int getAns(int a, int b, int ans) {
    if (a == 0) {
        return ans;
    }
    if ((a & 1) == 1) {
        ans += b;
    }
    return getAns(a >> 1, b << 1, ans);
}

面试题 08.06. 汉诺塔问题
在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。
你需要原地修改栈。

示例1:
输入:A = [2, 1, 0], B = [], C = []
输出:C = [2, 1, 0]

示例2:
输入:A = [1, 0], B = [], C = []
输出:C = [1, 0]

提示:
A中盘子的数目不大于14个。

public void hanota(List A, List B, List C) {
    move(A, B, C, A.size());
}

private void move(List from, List other, List to, int len) {
    if (len == 1) {
        to.add(from.remove(from.size() - 1));
        return;
    }
    move(from, to, other, len - 1);
    to.add(from.remove(from.size() - 1));
    move(other, from, to, len - 1);
}

面试题 08.07. 无重复字符串的排列组合
无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。

示例1:
输入:S = “qwe”
输出:[“qwe”, “qew”, “wqe”, “weq”, “ewq”, “eqw”]

示例2:
输入:S = “ab”
输出:[“ab”, “ba”]

提示:
字符都是英文字母。
字符串长度在[1, 9]之间。

我的原来的答案:

int k = 0;
public String[] permutation(String S) {
    Set characters = new HashSet<>();
    char[] chars = S.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        characters.add(chars[i]);
    }
    String[] ans = new String[A(S.length())];
    char[] anss = new char[S.length()];
    addAns(ans, characters, anss, characters.size(), characters.size());
    return ans;
}

private int A(int k) {
    if (k == 2) {
        return k;
    }
    return k * A(k - 1);
}

private void addAns(String[] ans, Set characters, char[] anss, int size, int len) {
    if (size == 0) {
        ans[k++] = new String(anss);
        return;
    }
    List list = new ArrayList(characters);
    for (Character c : list) {
        anss[len - size] = c;
        characters.remove(c);
        addAns(ans, characters, anss, size - 1, len);
        characters.add(c);
    }
}

看了最佳答案后,新的答案:

int k = 0;
public String[] permutation(String S) {
    char[] chars = S.toCharArray();
    int len = S.length();
    String[] ans = new String[A(S.length())];
    doAns(ans, chars, 0, len);
    return ans;
}

private void doAns(String[] ans, char[] chars, int s, int len) {
    if (s == len - 1) {
        ans[k++] = new String(chars);
        return;
    }
    doAns(ans, chars, s + 1, len);
    for (int i = s + 1; i < len; i++) {
        change(chars, s, i);
        doAns(ans, chars, s + 1, len);
        change(chars, s, i);
    }
}

private void change(char[] chars, int y, int x) {
    char c = chars[y];
    chars[y] = chars[x];
    chars[x] = c;
}

private int A(int k) {
    if (k == 2) {
        return k;
    }
    return k * A(k - 1);
}

面试题 08.08. 有重复字符串的排列组合

有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。

示例1:
输入:S = “qqe”
输出:[“eqq”,“qeq”,“qqe”]

示例2:
输入:S = “ab”
输出:[“ab”, “ba”]

提示:
字符都是英文字母。
字符串长度在[1, 9]之间。

int k = 0;
public String[] permutation(String S) {
    char[] chars = S.toCharArray();
    Arrays.sort(chars);
    int len = S.length();
    String[] ans = new String[getLen(chars)];
    doAns(ans, chars, 0, len);
    return ans;
}

private int getLen(char[] chars) {
    int[] nums = new int[128];
    for (int i = 0; i < chars.length; i++) {
        nums[chars[i]]++;
    }
    int ans = A(chars.length);
    for (int i = 0; i < 128; i++) {
        if (nums[i] > 1) {
            ans /= A(nums[i]);
        }
    }
    return ans;
}

private int A(int k) {
    if (k == 1) {
        return k;
    }
    return k * A(k - 1);
}


private void doAns(String[] ans, char[] chars, int s, int len) {
    if (s == len - 1) {
        ans[k++] = new String(chars);
        return;
    }
    doAns(ans, chars, s + 1, len);
    for (int i = s + 1; i < len; i++) {
        if (chars[i] == chars[s] || chars[i] == chars[i - 1]) {
            continue;
        }
        change(chars, s, i);
        doAns(ans, chars, s + 1, len);
        change(chars, s, i);
    }
}

private void change(char[] chars, int y, int x) {
    char c = chars[y];
    chars[y] = chars[x];
    chars[x] = c;
}

面试题 08.09. 括号
括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。

说明:解集不能包含重复的子集。

例如,给出 n = 3,生成结果为:

[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]

public List generateParenthesis(int n) {
    char[] chars = new char[n * 2];
    List ans = new ArrayList<>();
    addStr(ans, chars, 0, 0, n);
    return ans;
}

private void addStr(List ans, char[] chars, int left, int k, int n) {
    if (k == 2 * n) {
        ans.add(new String(chars));
        return;
    }
    if (left < n) {
        chars[k] = '(';
        addStr(ans, chars, left + 1, k + 1, n);
    }
    if (k - left < left) {
        chars[k] = ')';
        addStr(ans, chars, left, k + 1, n);
    }
}

面试题 08.10. 颜色填充

颜色填充。编写函数,实现许多图片编辑软件都支持的“颜色填充”功能。给定一个屏幕(以二维数组表示,元素为颜色值)、一个点和一个新的颜色值,将新颜色值填入这个点的周围区域,直到原来的颜色值全都改变。

示例1:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出:[[2,2,2],[2,2,0],[2,0,1]]
解释:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。

说明:
image 和 image[0] 的长度在范围 [1, 50] 内。
给出的初始点将满足 0 <= sr < image.length 和 0 <= sc < image[0].length。
image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535]内。

public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
    if (image[sr][sc] == newColor) {
        return image;
    }
    color(image, sr, sc, image[sr][sc], newColor);
    return image;
}

private void color(int[][] image, int sr, int sc, int oldColor, int newColor) {
    if (sr < 0 || sr >= image.length || sc < 0 || sc >= image[0].length) {
        return;
    }
    if (image[sr][sc] != oldColor) {
        return;
    }
    image[sr][sc] = newColor;
    color(image, sr - 1, sc, oldColor, newColor);
    color(image, sr + 1, sc, oldColor, newColor);
    color(image, sr, sc - 1, oldColor, newColor);
    color(image, sr, sc + 1, oldColor, newColor);
}

面试题 08.11. 硬币
硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

示例1:
输入: n = 5
输出:2
解释: 有两种方式可以凑成总金额:
5=5
5=1+1+1+1+1

示例2:
输入: n = 10
输出:4
解释: 有四种方式可以凑成总金额:
10=10
10=5+5
10=5+1+1+1+1+1
10=1+1+1+1+1+1+1+1+1+1

public int waysToChange(int n) {
    int MOD = 1000000007;
    int[] ans5 = new int[n + 1];
    for (int i = 0; i <= n; i++) {
        ans5[i] = i / 5 + 1;
    }
    if (n < 10) {
        return ans5[n];
    }
    int[] ans10 = new int[n + 1];
    for (int i = 0; i < 10; i++) {
        ans10[i] = ans5[i];
    }
    for (int i = 10; i <= n; i++) {
        ans10[i] = (ans10[i - 10] + ans5[i]) % MOD;
    }
    if (n < 25) {
        return ans10[n];
    }
    int[] ans25 = new int[n + 1];
    for (int i = 0; i < 25; i++) {
        ans25[i] = ans10[i];
    }
    for (int i = 25; i <= n; i++) {
        ans25[i] = (ans25[i - 25] + ans10[i]) % MOD;
    }
    return ans25[n];
}	

面试题 08.12. 八皇后

设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。

注意:本题相对原题做了扩展

示例:
输入:4
输出:[[".Q…","…Q",“Q…”,"…Q."],["…Q.",“Q…”,"…Q",".Q…"]]
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],

["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]

public List> solveNQueens(int n) {
    List> ans = new ArrayList<>();
    boolean[] cha = new boolean[n * 2];
    boolean[] he = new boolean[n * 2];
    boolean[] zon = new boolean[n];
    char[][] charList = new char[n][n];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            charList[i][j] = '.';
        }
    }
    check(n, 0, cha, he, zon, ans, charList);
    return ans;

}

private void check(int n, int k, boolean[] cha, boolean[] he, boolean[] zon, List> ans, char[][] charList) {
    if (n == k) {
        List r = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            r.add(new String(charList[i]));
        }
        ans.add(r);
        return;
    }
    char[] res = charList[k];
    for (int i = 0; i < n; i++) {
        if (zon[i] || he[i + k] || cha[k - i + n]) {
            continue;
        }
        zon[i] = true;
        he[i + k] = true;
        cha[k - i + n] = true;
        res[i] = 'Q';
        check(n, k + 1, cha, he, zon, ans, charList);
        res[i] = '.';
        zon[i] = false;
        he[i + k] = false;
        cha[k - i + n] = false;
    }
}

面试题 08.13. 堆箱子

堆箱子。给你一堆n个箱子,箱子宽 wi、高hi、深di。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子。实现一种方法,搭出最高的一堆箱子。箱堆的高度为每个箱子高度的总和。
输入使用数组[wi, di, hi]表示每个箱子。

示例1:
输入:box = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
输出:6

示例2:
输入:box = [[1, 1, 1], [2, 3, 4], [2, 6, 7], [3, 4, 5]]
输出:10

提示:
箱子的数目不大于3000个。

public int pileBox(int[][] box) {
    if (box == null) {
        return 0;
    }
    int len = box.length;
    if (len == 0) {
        return 0;
    }
    if (len == 1) {
        return box[0][2];
    }
    //排序
    Arrays.sort(box, new Comparator() {
        @Override
        public int compare(int[] o1, int[] o2) {
            if (o1[2] != o2[2]) {
                return o1[2] - o2[2];
            }
            if (o1[1] != o2[1]) {
                return o1[1] - o2[1];
            }
            return o1[0] - o2[0];
        }
    });
    //保存答案
    int[] ans = new int[len + 1];
    //保存截止最大值
    int[] max = new int[len + 1];
    for (int i = 0; i < len; i++) {
        int value = box[i][2];
        ll:
        for (int j = i - 1; j >= 0; j--) {
            //如果截止没有更大,就直接结束
            if (value >= box[i][2] + max[j + 1]) {
                break;
            }
            for (int k = 0; k < 3; k++) {
                //不符合的直接跳过
                if (box[i][k] <= box[j][k]) {
                    continue ll;
                }
            }
            value = box[i][2] + ans[j];
        }
        ans[i] = value;
        max[i + 1] = Math.max(value, max[i]);
    }
    return max[len];
}

面试题 08.14. 布尔运算

给定一个布尔表达式和一个期望的布尔结果 result,布尔表达式由 0 (false)、1 (true)、& (AND)、 | (OR) 和 ^ (XOR) 符号组成。实现一个函数,算出有几种可使该表达式得出 result 值的括号方法。

示例 1:
输入: s = “1^0|0|1”, result = 0
输出: 2
解释: 两种可能的括号方法是
1^(0|(0|1))
1^((0|0)|1)

示例 2:
输入: s = “0&0&0&1^1|0”, result = 1
输出: 10

提示:
运算符的数量不超过 19 个

//最优规划的做法
public int countEval(String s, int result) {
    if (result < 0 || result > 1) {
        return 0;
    }
    if (s == null || s.length() == 0) {
        return 0;
    }
    char[] chars = s.toCharArray();
    int len = chars.length;
    int[][][] ans = new int[s.length()][s.length()][2];
    for (int i = 0; i < len; i += 2) {
        ans[i][i][chars[i] - '0'] = 1;
    }
    //表示计算的长度
    for (int i = 2; i < len; i += 2) {
        //j表示计算的起点
        for (int j = 0; j < len - i; j += 2) {
            //k表示在哪分割计算
            for (int k = j + 1; k < j + i; k += 2) {
                if (chars[k] == '&') {
                    ans[j][j + i][1] += ans[j][k - 1][1] * ans[k + 1][i + j][1];
                    ans[j][j + i][0] += ans[j][k - 1][0] * ans[k + 1][i + j][1] +
                            ans[j][k - 1][1] * ans[k + 1][i + j][0] +
                            ans[j][k - 1][0] * ans[k + 1][i + j][0];
                } else if (chars[k] == '|') {
                    ans[j][j + i][1] += ans[j][k - 1][1] * ans[k + 1][i + j][1] +
                            ans[j][k - 1][0] * ans[k + 1][i + j][1] +
                            ans[j][k - 1][1] * ans[k + 1][i + j][0];
                    ans[j][j + i][0] += ans[j][k - 1][0] * ans[k + 1][i + j][0];
                } else if (chars[k] == '^') {
                    ans[j][j + i][1] += ans[j][k - 1][1] * ans[k + 1][i + j][0] +
                            ans[j][k - 1][0] * ans[k + 1][i + j][1];
                    ans[j][j + i][0] += ans[j][k - 1][0] * ans[k + 1][i + j][0] +
                            ans[j][k - 1][1] * ans[k + 1][i + j][1];
                }
            }
        }
    }
    return ans[0][len - 1][result];
}

你可能感兴趣的:(算法,leetcode)