LeetCode-20200817-20200823

9 篇文章 0 订阅

1 平衡二叉树

  • 题目。给定一个二叉树,判断它是否是高度平衡的二叉树。
    本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
  • 思路。递归求解即可。左子树和右子树都是平衡二叉树并且左右子树的高度差小于等于1。
  • 代码。
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) {
            return true;
        }

        return isBalanced(root.left) && isBalanced(root.right) && Math.abs(depth(root.left) - depth(root.right)) <= 1;
    }

    private int depth(TreeNode root) {
        if (root == null) {
            return 0;
        }

        return Math.max(depth(root.left), depth(root.right)) + 1;
    }
}

2 有序链表转换二叉搜索树

  • 题目。给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
    本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree
  • 思路。可以将有序链表的值存储在一个数组中,这样可以直接使用数组下标取到节点值。
  • 代码。
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode sortedListToBST(ListNode head) {
        if (head == null) {
            return null;
        }

        List<Integer> list = get(head);
        Integer[] val = list.toArray(new Integer[list.size()]);
        int mid = val.length / 2;
        TreeNode root = new TreeNode(val[mid]);
        root.left = f(val, 0, mid - 1);
        root.right = f(val, mid + 1, val.length - 1);
        return root;
    }

    private TreeNode f(Integer[] val, int i, int j) {
        if (i > j) {
            return null;
        }

        if (i == j) {
            return new TreeNode(val[i]);
        }

        int mid = i + (j - i) / 2;
        TreeNode r = new TreeNode(val[mid]);
        r.left = f(val, i, mid - 1);
        r.right = f(val, mid + 1, j);
        return r;
    }

    private List<Integer> get(ListNode head) {
        List<Integer> list = new ArrayList<>();
        ListNode cur = head;
        while (cur != null) {
            list.add(cur.val);
            cur = cur.next;
        }

        return list;
    }
}

3 回文子串

  • 题目。给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
    具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
    示例 1:
    输入:“abc”
    输出:3
    解释:三个回文子串: “a”, “b”, “c”
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/palindromic-substrings
  • 思路。遇到回文串的题目,自然而然可以想到Manacher算法,该算法可以用O(N)的时间复杂度求解出一个字符串的最长回文子串。另外,求解字符串中的回文串时,可以考虑从某个字符开始,向左右两个方向扩的思路。
  • 代码。
class Solution {
    public int countSubstrings(String s) {
        int n = s.length(), ans = 0;
        for (int i = 0; i < 2 * n - 1; ++i) {
            int l = i / 2, r = i / 2 + i % 2;
            while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {
                --l;
                ++r;
                ++ans;
            }
        }
        return ans;
    }

}

4 扫雷游戏

  • 题目。让我们一起来玩扫雷游戏!
    给定一个代表游戏板的二维字符矩阵。 ‘M’ 代表一个未挖出的地雷,‘E’ 代表一个未挖出的空方块,‘B’ 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字(‘1’ 到 ‘8’)表示有多少地雷与这块已挖出的方块相邻,‘X’ 则表示一个已挖出的地雷。
    现在给出在所有未挖出的方块中(‘M’或者’E’)的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板:
    如果一个地雷(‘M’)被挖出,游戏就结束了- 把它改为 ‘X’。
    如果一个没有相邻地雷的空方块(‘E’)被挖出,修改它为(‘B’),并且所有和其相邻的未挖出方块都应该被递归地揭露。
    如果一个至少与一个地雷相邻的空方块(‘E’)被挖出,修改它为数字(‘1’到’8’),表示相邻地雷的数量。
    如果在此次点击中,若无更多方块可被揭露,则返回面板。
    示例 1:
    输入:
    [[‘E’, ‘E’, ‘E’, ‘E’, ‘E’],
    [‘E’, ‘E’, ‘M’, ‘E’, ‘E’],
    [‘E’, ‘E’, ‘E’, ‘E’, ‘E’],
    [‘E’, ‘E’, ‘E’, ‘E’, ‘E’]]
    Click : [3,0]
    输出:
    [[‘B’, ‘1’, ‘E’, ‘1’, ‘B’],
    [‘B’, ‘1’, ‘M’, ‘1’, ‘B’],
    [‘B’, ‘1’, ‘1’, ‘1’, ‘B’],
    [‘B’, ‘B’, ‘B’, ‘B’, ‘B’]]
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/minesweeper
  • 思路。这道题需要首先读懂题意。可以从给定的初始点开始进行bfs,每次向看下周围有多少雷,如果当前位置周围有雷则标记当前位置有几个雷;如果当前位置没有雷,那么将当前位置周围的E位置加入到队列继续求解。在代码实现时,我们可以通过二位数组表示方向,使用以为数组表示坐标。
  • 代码。
class Solution {
     public char[][] updateBoard(char[][] board, int[] click) {
        if (board == null || board.length == 0 || board[0] == null || board[0].length == 0 || click == null || click.length != 2) {
            return board;
        }

        int r = board.length;
        int c = board[0].length;
        int[][] dir = new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
        boolean[][] visited = new boolean[r][c];
        Queue<int[]> queue = new LinkedList<>();
        queue.add(click);
        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            int x = cur[0];
            int y = cur[1];
            if (visited[x][y]) {
                continue;
            }
            
            visited[x][y] = true;
            if (board[x][y] == 'M') {
                board[x][y] = 'X';
                return board;
            }

            int mineNumber = 0;
            for (int[] d : dir) {
                int p = x + d[0];
                int q = y + d[1];
                if (p >= 0 && p < r && q >= 0 && q < c) {
                    if (board[p][q] == 'M') {
                        mineNumber++;
                    }
                }
            }

            // 当前位置x y周围没有雷
            if (mineNumber == 0) {
                board[x][y] = 'B';
                // 将x y周围没有处理过的位置,也就是周围的E加入队列
                for (int[] d : dir) {
                    int p = x + d[0];
                    int q = y + d[1];
                    if (p >= 0 && p < r && q >= 0 && q < c && board[p][q] == 'E') {
                        queue.add(new int[]{p, q});
                    }
                }
            } else {
                board[x][y] = (char)(mineNumber + '0');
            }
        }

        return board;
    }
}

5 二叉树的最小深度

  • 题目。给定一个二叉树,找出其最小深度。
    最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
    说明: 叶子节点是指没有子节点的节点。
    示例:
    给定二叉树 [3,9,20,null,null,15,7],

    3
    /
    9 20
    /
    15 7
    返回它的最小深度 2.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree

  • 思路。注意到这里的最小深度定义的是到叶子节点的最小深度,所以递归求解时如果到了null,我们将深度置为Integer.MAX_VALUE而不是0,然后再取左右子树最小深度。
  • 代码。
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }

        if (root != null && root.left == null && root.right == null) {
            return 1;
        }

        int leftMin = minDepth(root.left);
        leftMin = leftMin == 0 ? Integer.MAX_VALUE : leftMin;
        int rightMin = minDepth(root.right);
        rightMin = rightMin == 0 ? Integer.MAX_VALUE : rightMin;
        return 1 + Math.min(rightMin, leftMin);
    }
}

6 24点游戏

  • 题目。你有 4 张写有 1 到 9 数字的牌。你需要判断是否能通过 *,/,+,-,(,) 的运算得到 24。
    示例 1:
    输入: [4, 1, 8, 7]
    输出: True
    解释: (8-4) * (7-1) = 24
    示例 2:
    输入: [1, 2, 1, 2]
    输出: False
    注意:
    除法运算符 / 表示实数除法,而不是整数除法。例如 4 / (1 - 2/3) = 12 。
    每个运算符对两个数进行运算。特别是我们不能用 - 作为一元运算符。例如,[1, 1, 1, 1] 作为输入时,表达式 -1 - 1 - 1 - 1 是不允许的。
    你不能将数字连接在一起。例如,输入为 [1, 2, 1, 2] 时,不能写成 12 + 12 。
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/24-game

  • 思路。先从4个数中选两个做排列,然后从加减乘除中选择一个符号,得到一个数。共有A(4,2)*4=48种可能性
    然后从剩下的三个数中选择两个做排列,然后从加减乘除中选择一个符号,得到一个数。共有A(3,2)4=24种可能性
    剩下的两个数做排列,看得到的数是不是24即可。共有A(2,2)4=8种可能性。综上所述,一共有4824
    8=9216种可能性。需要考虑的是这里的除法是浮点数运算,需要考虑误差。
    另外加法和乘法都满足交换律,因此如果选择的运算操作是加法或乘法,则对于选出的 22 个数字不需要考虑不同的顺序,在遇到第二种顺序时可以不进行运算,直接跳过。

  • 代码。

class Solution {
    private static final int TARGET = 24;
    private static final double EPSILON = 1e-6;
    public boolean judgePoint24(int[] nums) {
        if (nums == null || nums.length == 0) {
            return false;
        }

        List<Double> list = new ArrayList<>(4);
        for (int num : nums) {
            list.add((double) num);
        }

        return canReachTarget(list);
    }

    private boolean canReachTarget(List<Double> list) {
        if (list == null || list.size() == 0) {
            return false;
        }

        // list中只有一个数了,看是不是等于24
        if (list.size() == 1) {
            if (Math.abs(list.get(0) - TARGET) <= EPSILON) {
                return true;
            } else {
                return false;
            }
        }
        
        int size = list.size();
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                if (i == j) {
                    continue;
                }

                // 从list中取两个数
                double p = list.get(i);
                double q = list.get(j);
                List<Double> newList = new ArrayList<>();
                for (int k = 0; k < size; k++) {
                    if (k != i && k != j) {
                        newList.add(list.get(k));
                    }
                }
                
                // 从4个符号中取一个
                double newNumber;
                for (int k = 0; k < 4; k++) {
                    // 认为0代表加法
                    if (k == 0) {
                        newNumber = p + q;
                    } else if (k == 1) {
                        // 认为1代表减法
                        newNumber = p - q;
                    } else if (k == 2) {
                        // 认为2代表乘法
                        newNumber = p * q;
                    } else {
                        // 认为3代表除法
                        if (q != 0) {
                            newNumber = p / q;
                        } else {
                            return false;
                        }
                    }
                    newList.add(newNumber);
                    if (canReachTarget(newList)) {
                        return true;
                    } else {
                        newList.remove(newNumber);
                    }
                }
            }
        }
        return false;
    }
}

7 数字范围按位与

  • 题目。给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
    示例 1:
    输入: [5,7]
    输出: 4
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/bitwise-and-of-numbers-range
  • 思路。该题可转化为找m和n对应的二进制字符串的最长公共前缀,这个最长公共前缀和后面的0组成答案。
  • 代码。
class Solution {
    public int rangeBitwiseAnd(int m, int n) {
        int shift = 0;;
        while (m < n) {
            m = m >> 1;
            n = n >> 1;
            shift++;
        }

        return m << shift;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值