码迷,mamicode.com
首页 > 其他好文 > 详细

🔥 LeetCode 热题 HOT 100(31-40)

时间:2021-07-05 18:51:34      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:character   mirror   状态   思路   tps   else   sea   转移   row   

75. 颜色分类

思路:将 2 往后放,0 往前放,剩余的1自然就放好了。

  • 使用双指针:left、right 分别指向待插入的 0 和 2 的位置,初始 left 指向数组头,right 指向数组尾部。
  • 从头开始遍历数组,若当前位置数为 2 则与 right 所指向元素互换,然后 right 左移,直到当前位置元素不为2;
  • 当前位置元素若为 0 则 和 left 所指元素互换,然后 left 右移。随后接着遍历,直到 和 right相遇。
class Solution {
    public void sortColors(int[] nums) {
        int left = 0;
        int right = nums.length - 1;

        for (int i = 0; i <= right; i++) {
            //将2往后放
            while (i <= right && nums[i] == 2) {
                swap(nums, i, right);
                right--;
            }

            //将0往前放
            if (nums[i] == 0) {
                swap(nums, i, left);
                left++;
            }
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

76. 最小覆盖子串

思路:标准滑动窗口

class Solution {
    public String minWindow(String s, String t) {
        //记录 t 中字符在 window 中的出现频次
        Map<Character, Integer> window = new HashMap<>();

        //记录 t 中各个字符的频次
        Map<Character, Integer> need = new HashMap<>();
        for (int i = 0; i < t.length(); i++) {
            need.put(t.charAt(i), need.getOrDefault(t.charAt(i), 0) + 1);
        }

        //窗口边界,左闭右开
        int left = 0, right = 0;
        // t 中字符在 window 中已经匹配的个数
        int match = 0;

        //最小子串的起始位置和长度
        int start = 0, minLen = Integer.MAX_VALUE;
        while (right < s.length()) {
            //窗口扩张(右边界右移)
            char rightChar = s.charAt(right);
            right++;

            //如当前 rightChar 是 t 中的字符
            if (need.containsKey(rightChar)) {
                // window 中对应次数加 1
                window.put(rightChar, window.getOrDefault(rightChar, 0) + 1);
                // 仅当 rightChar 在 window 中的频次 小于等于 t 中的频次时才说明新匹配了一个字符(想想t中某个字符出现多次的情况)
                if (window.get(rightChar).compareTo(need.get(rightChar)) <= 0) {
                    match++;
                }
            }

            //如果 window 中已经包含了 t 中所有字符
            while (match == t.length()) {
                int  tempLen = right - left;
                if (tempLen < minLen) {
                    minLen = tempLen;
                    start = left;
                }

                //收缩窗口(左边界右移)
                char leftChar = s.charAt(left);
                left++;

                if (need.containsKey(leftChar)) {
                    if (window.get(leftChar).compareTo(need.get(leftChar)) <= 0) {
                        match--;
                    }
                    window.put(leftChar, window.get(leftChar) - 1);
                }
            }
        }

        return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen);
    }
}

78. 子集

思路:典型回溯法

lass Solution {
    public List<List<Integer>> subsets(int[] nums) {
        LinkedList<Integer> track = new LinkedList<>();
        dfs(nums, track, 0);
        return res;
    }

    private List<List<Integer>> res = new LinkedList<>();
    private void dfs (int[] nums, LinkedList<Integer> track, int start) {
        res.add(new LinkedList<>(track));

        //通过start来控制当前可以选择的列表
        for (int i = start; i < nums.length; i++) {
            //选择
            track.offerLast(nums[i]);
            dfs(nums, track, i + 1);
            //撤销选择
            track.pollLast();
        }
    }
}

//                  {1, 2, 3}对应递归树:
//                                []
//                       1        2        3			
//                   12   13    23
//                  123

79. 单词搜索

思路:直接回溯

class Solution {
    public boolean exist(char[][] board, String word) {
        boolean[][] visited = new boolean[board.length][board[0].length];

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == word.charAt(0)) {
                    if (dfs(board, word, 0, visited, i, j)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    private boolean dfs(char[][] board, String word, int index, boolean[][] visited, int row, int col) {
        //base case
        if (word.length() == index) {
            return true;
        }

        if (!isValid(board, row, col)) {
            return false;
        }
        if (visited[row][col]) {
            return false;
        }
        if (board[row][col] != word.charAt(index)) {
            return false;
        }

        //标记访问过的位置
        visited[row][col] = true;
        
        boolean res = dfs(board, word, index + 1, visited, row + 1, col) || 
                      dfs(board, word, index + 1, visited,  row, col + 1) ||
                      dfs(board, word, index + 1, visited,  row - 1, col) ||
                      dfs(board, word, index + 1, visited,  row, col - 1);
        
        //撤销标记
        visited[row][col] = false;

        return res;
    }

    private boolean isValid(char[][] board, int row, int col) {
        if (row >= 0 && row < board.length && col >= 0 && col < board[0].length) {
            return true;
        } else {
            return false;
        }
    }
}

推荐题解:回溯算法(Java)

84. 柱状图中最大的矩形

思路:单调递增栈,依次遍历数组,大于等于栈顶元素直接入栈,小于则弹栈并计算一次面积。

class Solution {
    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        int[] newHeight = new int[len + 2];

        //将 heights 复制到 newHeight,同时将首尾各填充一个 -1
        newHeight[0] = -1;
        newHeight[len - 1] = -1;
        for (int i = 1; i <= len; i++) {
            newHeight[i] = heights[i - 1];
        }

        int maxArea = 0;
        Deque<Integer> stack = new LinkedList<>();
        for (int i = 0; i < newHeight.length; i++) {
            //出栈
            while (!stack.isEmpty() && newHeight[stack.peek()] > newHeight[i]) {
                int high = newHeight[stack.pop()];
                int width = i - stack.peek() - 1;	// 下标 [stack.peek() + 1, i - 1] 对应元素都 大于等于 high
                int area = high * width;
                maxArea = Math.max(area, maxArea);
            }

            //入栈
            stack.push(i);
        }

        return maxArea;
    }
}

推荐题解:详解单调栈,???♀?必须秒懂!

85. 最大矩形

思路:将该题转换为上一题(84. 柱状图中最大的矩形)。如下图,分别获取以每一行为底的柱状图,并计算当前柱状图所能围城的最大矩形面积,最后取最大值。

技术图片

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length <= 0 || matrix[0].length <= 0) {
            return 0;
        }
        int row = matrix.length;
        int col = matrix[0].length;
        
        int maxArea = 0;

        //根据二维矩阵获取柱状图对应数组
        int[] tempHeight = new int[col];
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (matrix[i][j] == ‘1‘) {
                    tempHeight[j] += 1;
                } else {
                    tempHeight[j] = 0;
                }
            }
            maxArea = Math.max(maxArea, largestRectangleArea(tempHeight));
        }

        return maxArea;
    }

    //84. 柱状图中最大的矩形
    private int largestRectangleArea(int[] nums) {
        int len = nums.length;

        int[] newHeight = new int[len + 2];
        newHeight[0] = -1;
        newHeight[len + 1] = -1;

        for (int i = 0; i < len; i++) {
            newHeight[i + 1] = nums[i];
        }

        int maxArea = 0;
        Deque<Integer> stack = new LinkedList<>();
        for (int i = 0; i < newHeight.length; i++) {
            while (!stack.isEmpty() && newHeight[stack.peek()] > newHeight[i]) {
                int high = newHeight[stack.pop()];
                int width = i - stack.peek() - 1;
                int area = high * width;
                maxArea = Math.max(area, maxArea);
            }

            stack.push(i);
        }

        return maxArea;
    }
}

94. 二叉树的中序遍历

非递归解法:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new LinkedList<>();
        if (root == null) {
            return res;
        }
            
        TreeNode temp = root;
        Deque<TreeNode> stack = new LinkedList<>();
        while (temp != null || !stack.isEmpty()) {
            while (temp != null) {
                stack.push(temp); // 加入栈
                temp = temp.left; // 到最左边结点停止
            }

            temp = stack.pop();   // 访问栈顶元素
            res.add(temp.val);

            temp = temp.right;    //下一个遍历的元素是temp的右子树的最左边结点
        }

        return res;
    }
}

96. 不同的二叉搜索树

思路:动态规划

class Solution {
    public int numTrees(int n) {
        // 由小到大的 n 个结点所能组成的不同二叉搜索树个数
        int[] dp = new int[n + 1];

        //base case
        dp[0] = 1;
        dp[1] = 1;

        //状态转移 dp[i] = dp[0]dp[i - 1] + dp[1]dp[i - 2] ... + ... dp[i - 1]dp[0],即:sum(dp[j - 1] + dp[i - j]), j从1到i
        for (int i = 2; i < n + 1; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }

        return dp[n];
    }
}

推荐题解:画解算法:96. 不同的二叉搜索树

98. 验证二叉搜索树

/**
 * 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 boolean isValidBST(TreeNode root) {
        return isValidBST(root, null, null);
    }

    //二叉搜索树的每个结点都有一个上下界(除了根节点)
    private boolean isValidBST(TreeNode node, TreeNode low, TreeNode high) {
        //base case
        if (node == null) {
            return true;
        }

        //base case
        if (low != null && node.val <= low.val) return false;
        if (high != null && node.val >= high.val) return false;

        boolean ret = isValidBST(node.left, low, node) && isValidBST(node.right, node, high);
        return ret;
    }
}

推荐题解:验证二叉搜索树(BST:给子树上所有节点都加一个边界?)

101. 对称二叉树

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isMirror(root, root);
    }

    private boolean isMirror(TreeNode node1, TreeNode node2) {
        if (node1 == null && node2 == null) {
            return true;
        } 
        
        // 联系前面的判断,此处表示只有一个为null
        if (node1 == null || node2 == null) {
            return false;
        }

        return (node1.val == node2.val) && isMirror(node1.left, node2.right) && isMirror(node1.right, node2.left);
    }
}

推荐题解:画解算法:101. 对称二叉树

🔥 LeetCode 热题 HOT 100(31-40)

标签:character   mirror   状态   思路   tps   else   sea   转移   row   

原文地址:https://www.cnblogs.com/winlsr/p/14967364.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!