【算法面试题汇总】LeetBook列表的算法面试题汇总---动态规划题目及答案

整理不易留个小心心呗🥰
如果有更好的或者是我有错的地方还请各位大佬指出哦
有些是copy的还望不要介意

至少有k个重复字符的最长子串

题目描述:
给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。

示例:

输入:s = "ababbc", k = 2
输出:5
解释:最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次。

提示:
1 <= s.length <= 104
s 仅由小写英文字母组成
1 <= k <= 105
  • 分治

    对于字符串 ss,如果存在某个字符ch,它的出现次数大于 00 且小于 kk,则任何包含 ch 的子串都不可能满足要求。也就是说,我们将字符串按照 ch 切分成若干段,则满足要求的最长子串一定出现在某个被切分的段内,而不能跨越一个或多个段。因此,可以考虑分治的方式求解本题。

class Solution {
   
    public int longestSubstring(String s, int k) {
   
        return dfs(s,0,s.length()-1,k);
    }
    public int dfs(String s,int left,int right,int k){
   
        //统计每个字符出现的次数
        int[] c = new int[26];
        for(int i=left;i<=right;i++){
   
            c[s.charAt(i) - 'a']++;
        }

        //统计小于k的字符
        char split = 0;
        for(int i=0;i<26;i++){
   
            if(c[i]>0 && c[i]<k){
   
                split = (char)(i + 'a');
                break;
            }
        }
        //全部都大于等于k个数,则返回整个字符串
        if(split == 0){
   
            return right-left+1;
        }

        int l=left;
        int ans=0;
        while(l <= right){
   
            //跳过小于k的字符
            while(l<=right && s.charAt(l) == split){
   
                l++;
            }
            if(l>right){
   
                break;
            }
            int start=l;
            while(l<=right && s.charAt(l) != split){
   
                l++;
            }
            ans = Math.max(ans,dfs(s,start,l-1,k));
        }
        return ans;
    }
}
  • 滑动窗口

    不能用二分,因为不具有二段性质

    假设此时子串长度为t的这一区间满足要求,t+1长度的区间不一定满足要求:

    若新的字符在原有区间出现过,则t+1长度满足;

    若新的字符在原有区间没有出现过,则t+1长度不满足

    因此我们无法是使用「二分」,相应的也无法直接使用「滑动窗口」思路的双指针

    因为双指针其实也是利用了二段性质,当一个指针确定在某个位置,另外一个指针能够落在某个明确的分割点,使得左半部分满足,右半部分不满足。

    当确定了窗口内所包含的字符数量时,区间重新具有了二段性质

    利用字符数量有限性(可枚举)作为切入点,使得「答案子串的左边界左侧的字符以及右边界右侧的字符一定不会出现在子串中」这一性质在双指针的实现下具有单调性,也就是「让区间重新具有二段性质」。

class Solution {
   
    public int longestSubstring(String s, int k) {
   
        int n = s.length();
        int ans = 0;
        char[] c = s.toCharArray();
        int[] cnt = new int[26];
        for(int p=1;p<=26;p++){
   
            Arrays.fill(cnt,0);
            //total表示在这个区间内所有字符种类的数量
            //sum表示满足大于等于k的字符种类数量
            int l=0,total=0,sum=0;
            for(int r=0;r<n;r++){
   
                int t = c[r] - 'a';
                cnt[t]++;
                //如果添加进cnt后等于1,则表示多一种种类
                if(cnt[t] == 1) total++;
                //如果添加进cnt后等于k,则表示满足条件的字符数量加1
                if(cnt[t] == k) sum++;
                //当超过限定数量p,则左指针右移
                while(total > p){
   
                    int temp = c[l++] - 'a';
                    cnt[temp]--;
                    //如果减掉后等于0,则种类减1
                    if(cnt[temp] == 0)total--;
                    //如果减掉后小于k,则满足条件的字符数量-1
                    if(cnt[temp] == k-1)sum--;
                }
                //当所有字符都符合要求,更新答案
                if(total == sum){
   
                    ans = Math.max(ans, r-l+1);
                }
            }
        }
        return ans;
    }
}

二叉树中的最大路径和

题目描述:
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和

示例:
在这里插入图片描述

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42
  • 代码实现
/**
 * 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 {
   
    int res = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
   
        maxValue(root);
        return res;
    }
    public int maxValue(TreeNode root){
   
        if(root == null){
   
            return 0;
        }
        //递归计算左右子节点的最大贡献值
        //大于0才选取
        int left = Math.max(maxValue(root.left),0);
        int right = Math.max(maxValue(root.right),0);
        //更新最大路径和
        res = Math.max(left + right+root.val , res);
        //返回节点的最大贡献值
        //最大贡献值:等于该节点的值与其子节点的最大贡献值之和
        //叶节点的最大贡献值为该节点的值
        return Math.max(left,right)+root.val;
    }
}

最长连续序列

题目描述:
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值