博客记录-day162-力扣(dp编辑距离,回文子串)

112 阅读4分钟

一、力扣

1、子结构判断

LCR 143. 子结构判断

image.png

class Solution {
    TreeNode B;
    boolean res;

    public boolean isSubStructure(TreeNode A, TreeNode B) {
        // 空树不能作为子结构
        if (B == null)  return false;
        // 初始化目标子结构
        this.B = B;
        // 重置结果标记
        this.res = false;
        // 从根节点开始深度优先遍历主树
        dfs(A);
        return res;
    }

    public void dfs(TreeNode A) {
        if (A == null)  return;
        
        // 发现值匹配的节点,进行结构校验
        if (A.val == B.val && check(A, B)) {
            res = true; // 找到匹配,设置结果
        }
        
        // 递归遍历左右子树(即使已找到结果,仍需遍历完整棵树)
        dfs(A.left);
        dfs(A.right);
    }

    public boolean check(TreeNode fir, TreeNode sec) {
        // 子结构遍历完成,结构匹配
        if (sec == null)  return true;
        // 主树已遍历完但子结构未完成,结构不匹配
        if (fir == null)  return false;
        // 节点值不匹配
        if (fir.val != sec.val)  return false;
        
        // 递归校验左右子树
        return check(fir.left, sec.left) && check(fir.right, sec.right);
    }
}

2、! 字典序的第K小数字

440. 字典序的第K小数字

image.png

image.png

class Solution {
    public int findKthNumber(int n, int k) {
        //从根节点下面的第一个结点1开始遍历,由于数据范围很大,所以用long
        long cur = 1;
        //从1出发开始往后按字典序从小到大的顺序走k-1步到达的就是 字典序的第K小数字
        k -= 1;

        while (k > 0) {
            //得到以当前结点为根的所有子树节点数目
            int nodes = getNodes(n, cur);
            //如果k要大于当前根节点下所有子树结点的数目,就向右侧节点走(->2->3->4->5->6->7->8->9):字典序上升nodes位
            if (k >= nodes) {
                //减去已经遍历的个数
                k -= nodes;
                //根节点右移
                cur ++;
            } 
            //如果k小于当前根节点下所有子树结点的数目,说明答案就在当前根节点的子树结点中
            else {
                //减去根节点的数量1
                k -= 1;
                //将根结点移动到下一层(每一层右10个结点)
                cur *= 10;
            }
        }
        //最终k = 0时,就找到了答案
        return (int)cur;
    }

    // 计算以cur为根的子树节点数目,所有节点的值必须 <= n
    private int getNodes(int n, long cur){
        // 记录子树中的全部节点数目
        long totalNodes = 0; 
        // 当前节点右侧右边节点的值,用于计算一行有几个元素
        long next = cur + 1; 
        while(cur <= n){
            //取整行结点的个数,可能全部都满了,也可能是叶子结点,没有充满
            totalNodes += Math.min(n - cur + 1, next - cur);
            //cur - cur在当前层的第一个结点, next - cur右侧根结点的第一个结点
            next *= 10;
            cur *= 10;
        }
        return (int)totalNodes;
    }
}

3、不同的子序列

115. 不同的子序列

image.png

class Solution {
    public int numDistinct(String s, String t) {
        int m = s.length(), n = t.length();
        int[][] dp = new int[m + 1][n + 1];//dp[i][j] 为以i为结尾s子序列的出现j结尾子序列个数
        for (int i = 0; i < m + 1; i++) {
            dp[i][0] = 1;
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (s.charAt(i) == t.charAt(j)) {
                    dp[i + 1][j + 1] = dp[i][j] + dp[i][j + 1];
                } else {
                    dp[i + 1][j + 1] = dp[i][j + 1];
                }
            }
        }
        return dp[m][n];
    }
}

4、两个字符串的删除操作

583. 两个字符串的删除操作

image.png

dp[i][j]为使word1[:i]和word2[:j]相同的最小步数。

class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length(), n = word2.length();
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 0; i <= m; i++) {
            dp[i][0] = i;
        }
        for (int i = 0; i <= n; i++) {
            dp[0][i] = i;
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (word1.charAt(i) == word2.charAt(j)) {
                    dp[i + 1][j + 1] = dp[i][j];
                } else {
                    dp[i + 1][j + 1] = Math.min(dp[i][j + 1], dp[i + 1][j]) + 1;
                }
            }
        }
        return dp[m][n];
    }
}

5、编辑距离

72. 编辑距离

image.png

class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length(), n = word2.length();
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 0; i < m + 1; i++) {
            dp[i][0] = i;
        }
        for (int i = 0; i < n + 1; i++) {
            dp[0][i] = i;
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (word1.charAt(i) == word2.charAt(j)) {
                    dp[i + 1][j + 1] = dp[i][j];
                } else {
                    dp[i + 1][j + 1] = Math.min(dp[i][j + 1], Math.min(dp[i + 1][j], dp[i][j])) + 1;
                }
            }
        }
        return dp[m][n];
    }
}

6、回文子串

647. 回文子串

image.png

class Solution {
    public int countSubstrings(String s) {
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        int res = 0;
        for (int i = n - 1; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                if (s.charAt(i) == s.charAt(j)) {
                    if (j - i <= 1) {
                        res++;
                        dp[i][j] = true;
                    } else if (dp[i + 1][j - 1]) {
                        dp[i][j] = true;
                        res++;
                    }
                }
            }
        }
        return res;
    }
}

7、最长回文子序列

516. 最长回文子序列

image.png

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

8、最长回文子串

5. 最长回文子串

image.png

class Solution {
    public String longestPalindrome(String s) {
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        int len = 1;
        String res = s.substring(0, 1);
        for (int j = 1; j < n; j++) {
            for (int i = j; i >= 0; i--) {
                if (s.charAt(i) == s.charAt(j)) {
                    if (j - i <= 1) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }
                if (dp[i][j] && j - i + 1 > len) {
                    res = s.substring(i, j + 1);
                    len = j - i + 1;
                }
            }
        }
        return res;
    }
}