LeetCode 516. 最长回文子序列(区间dp) / 36. 有效的数独/73. 矩阵置零/496. 下一个更大元素 I / 456. 132 模式(特别的单调栈)

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 516. 最长回文子序列(区间dp) / 36. 有效的数独/73. 矩阵置零/496. 下一个更大元素 I / 456. 132 模式(特别的单调栈)相关的知识,希望对你有一定的参考价值。

516. 最长回文子序列

2021.8.12 每日一题

题目描述

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例 1:

输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。

示例 2:

输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。

提示:

1 <= s.length <= 1000
s 仅由小写英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

经典区间dp问题,注意遍历顺序就可以

class Solution {
    public int longestPalindromeSubseq(String s) {
        int l = s.length();
        int[][] dp = new int[l][l];
        for(int i = 0; i < l; i++){
            dp[i][i] = 1;
        }
        int max =1;
        for(int i = l - 2; i >= 0; i--){
            for(int j = i + 1; j < l; j++){
                dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                if(s.charAt(i) == s.charAt(j)){
                    dp[i][j] = Math.max(dp[i][j], dp[i + 1][j - 1] + 2);
                }
                max = Math.max(max, dp[i][j]);
            }
        }
        return max;
    }
}

区间dp,三叶姐给出的普遍思路:
1.从小到大枚举区间长度len
2.枚举左边下标l,根据区间长度计算出又端点r
3.求dp[l][r]

把这个模版也记住!!!

class Solution {
    public int longestPalindromeSubseq(String s) {
        int n = s.length();
        char[] cs = s.toCharArray();
        int[][] f = new int[n][n]; 
        for (int len = 1; len <= n; len++) {
            for (int l = 0; l + len - 1 < n; l++) {
                int r = l + len - 1;
                if (len == 1) {
                    f[l][r] = 1;
                } else if (len == 2) {
                    f[l][r] = cs[l] == cs[r] ? 2 : 1;
                } else {
                    f[l][r] = Math.max(f[l + 1][r], f[l][r - 1]);
                    f[l][r] = Math.max(f[l][r], f[l + 1][r - 1] + (cs[l] == cs[r] ? 2 : 0));
                }
            }
        }
        return f[0][n - 1];
    }
}


作者:AC_OIer
链接:https://leetcode-cn.com/problems/longest-palindromic-subsequence/solution/gong-shui-san-xie-qu-jian-dp-qiu-jie-zui-h2ya/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论区大佬思路,将字符串翻转,然后求两个字符串的最长公共子序列:

class Solution {
    public int longestPalindromeSubseq(String s) {
        int l = s.length();
        //翻转字符串
        String r = new StringBuffer(s).reverse().toString();
        //两个字符串的最长公共子序列
        int[][] dp = new int[l + 1][l + 1];

        for(int i = 1; i <= l; i++){
            for(int j = 1; j <= l; j++){
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                if(s.charAt(i - 1) == r.charAt(j - 1)){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
            }
        }
        return dp[l][l];
    }
}

36. 有效的数独

题目描述

请你判断一个 9x9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

注意:

一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。

示例 1:

输入:board =
[[“5”,“3”,".",".",“7”,".",".",".","."]
,[“6”,".",".",“1”,“9”,“5”,".",".","."]
,[".",“9”,“8”,".",".",".",".",“6”,"."]
,[“8”,".",".",".",“6”,".",".",".",“3”]
,[“4”,".",".",“8”,".",“3”,".",".",“1”]
,[“7”,".",".",".",“2”,".",".",".",“6”]
,[".",“6”,".",".",".",".",“2”,“8”,"."]
,[".",".",".",“4”,“1”,“9”,".",".",“5”]
,[".",".",".",".",“8”,".",".",“7”,“9”]]
输出:true

示例 2:

输入:board =
[[“8”,“3”,".",".",“7”,".",".",".","."]
,[“6”,".",".",“1”,“9”,“5”,".",".","."]
,[".",“9”,“8”,".",".",".",".",“6”,"."]
,[“8”,".",".",".",“6”,".",".",".",“3”]
,[“4”,".",".",“8”,".",“3”,".",".",“1”]
,[“7”,".",".",".",“2”,".",".",".",“6”]
,[".",“6”,".",".",".",".",“2”,“8”,"."]
,[".",".",".",“4”,“1”,“9”,".",".",“5”]
,[".",".",".",".",“8”,".",".",“7”,“9”]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

提示:

board.length == 9
board[i].length == 9
board[i][j] 是一位数字或者 ‘.’

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-sudoku
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

class Solution {
    public boolean isValidSudoku(char[][] board) {
        //用哈希表记录每一行,每一列,每一个宫内出现的数字
        //如果相同的就返回fasle
        //9行,9列,9个宫
        int l = board.length;
        boolean[][] row = new boolean[l][10];
        boolean[][] col = new boolean[l][10];
        boolean[][] mat = new boolean[l][10];

        for(int i = 0; i < l; i++){
            for(int j = 0; j < l; j++){
                if(board[i][j] == '.')
                    continue;
                int t = board[i][j] - '0';
                int idx = i / 3 * 3 + j / 3;
                if(row[i][t] || col[j][t] || mat[idx][t])
                    return false;
                row[i][t] = true;
                col[j][t] = true;
                mat[idx][t] = true;
            }
        }
        return true;
    }
}

73. 矩阵置零

题目描述

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

进阶:

一个直观的解决方案是使用  O(mn) 的额外空间,但这并不是一个好的解决方案。
一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
你能想出一个仅使用常量空间的解决方案吗?

示例 1:

输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]

示例 2:

输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

提示:

m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-2^31 <= matrix[i][j] <= 2^31 - 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/set-matrix-zeroes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

空间复杂度m+n的方法:

class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        boolean[] row = new boolean[m];
        boolean[] col = new boolean[n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == 0) {
                    row[i] = col[j] = true;
                }
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (row[i] || col[j]) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
}

主要是空间复杂度O1的方法难想

class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        //要用O1的空间,很自然会想到用特殊的数去标记需要置0的位置,但是矩阵中的数取了整型所有值,所以不行
        //然后想和m+n的解法一样,用一行一列去标记
        //很自然会想到用第一行和第一列
        //那么第一行和第一列本身用什么标记呢,就是两个变量
        //那么一个变量可以吗,当然可以
        //用一个变量去标记第一列是否需要置0
        //然后用第一列标记每一行是否需要置0,第一行去标记这一列
        //用第一行标记每一列是否需要置0
        boolean flag = false;
        for(int i = 0; i < m; i++){
            //第一列
            if(matrix[i][0] == 0)
                flag = true;
            for(int j = 1; j < n; j++){
                if(matrix[i][j] == 0)
                    matrix[i][0] = matrix[0][j] = 0;
            }
        }
        //这里考虑一下怎么修改这个状态
        //因为要用到第一行和第一列,所以需要先把别的行列修改了,再修改第一行和第一列
        //所以从下至上
        for(int i = m - 1; i >= 0; i--){
            for(int j = 1; j < n; j++){
                if(matrix[i][0] == 0 || matrix[0][j] == 0)
                    matrix[i][j] = 0;
            }
            //遍历完这一行,可以更改第一列的状态了
            if(flag)
                matrix[i][0] = 0;
        }
    }
}

496. 下一个更大元素 I

题目描述

给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。

请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

示例 1:

输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。
对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。
对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。

示例 2:

输入: nums1 = [2,4], nums2 = [1,2,3,4].
输出: [3,-1]
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出 -1 。

提示:

1 <= nums1.length <= nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 10^4
nums1和nums2中所有整数 互不相同
nums1 中的所有整数同样出现在 nums2 中

进阶:你可以设计一个时间复杂度为 O(nums1.length + nums2.length) 的解决方案吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-greater-element-i
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

这道题咋说呢,如果要实现最后复杂度的要求
应该算个中等题,单调栈思路

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        //记得上次是不会做的,尽管是简单题
        //思路:要在O1内找到比当前大的
        //首先处理nums2,用栈处理,单调栈,找第一个比自己大的,存入map中
        int l = nums2.length;
        Stack<Integer> stack = new Stack<>();
        Map<Integer, Integer> map = new HashMap<>();

        stack.push(nums2[0]);
        for(int i = 1; i < l; i++){
            int temp = nums2[i];
            while(!stack.isEmpty() && temp > stack.peek()){
                int p = stack.pop();
                map.put(p, temp);
            }
            stack.push(temp);
        }
        while(!stack.isEmpty()){
            map.put(stack.pop(), -1);
        }
        int[] res = new int[nums1.length];
        for(int i = 0; i < nums1.length; i++){
            int temp = nums1[i];
            res[i] = map.get(temp);
        }
        return res;
    }
}

456. 132 模式

题目描述

给你一个整数数组 nums ,数组中共有 n 个整数。132 模式的子序列 由三个整数 nums[i]、nums[j] 和 nums[k] 组成,并同时满足:i < j < k 和 nums[i] < nums[k] < nums[j] 。

如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [1,2,3,4]
输出:false
解释:序列中不存在 132 模式的子序列。

示例 2:

输入:nums = [3,1,4,2]
输出:true
解释:序列中有 1 个 132 模式的子序列: [1, 4, 2] 。

示例 3:

输入:nums = [-1,3,2,0]
输出:true
解释:序列中有 3 个 132 模式的的子序列:[-1, 3, 2]、[-1, 3, 0] 和 [-1, 2, 0] 。

提示:

n == nums.length
1 <= n <= 2 * 10^5
-10^9 <= nums[i] <= 10^9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/132-pattern
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

这道题我竟然还做过
先很自信的写了一个这样的代码

class Solution {
    public boolean find132pattern(int[] nums) {
        //单调栈
        //如果比当前栈顶元素小,就弹出,然后记录这个最小元素min
        //如果比栈顶元素大,就放入,然后遇到一个在min和栈顶之间的,就满足条件
        Stack<Integer> stack = new Stack<>();
        int l = nums.length;
        stack.push(nums[0]);
        int min = nums[0];
        for(int i = 1; i < l; i++){
            int temp = nums[i];
            if(temp > min && temp < stack.peek())
                return true;
            while(!stack.isEmpty() && stack.peek() >=

以上是关于LeetCode 516. 最长回文子序列(区间dp) / 36. 有效的数独/73. 矩阵置零/496. 下一个更大元素 I / 456. 132 模式(特别的单调栈)的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode 516 最长回文子序列

Leetcode刷题Python516. 最长回文子序列

LeetCode 516. 最长回文子序列

516. 最长回文子序列(Python)

LeetCode 516 最长回文子序列[动态规划] HERODING的LeetCode之路

区间DP入门