2024年2月21日小记

本文介绍了作者在LeetCode上刷题时遇到的四个挑战,包括最长增长子序列的两种动态规划解法,删除无效括号的剪枝策略,买卖股票的最佳时机(含冷冻期)以及戳气球问题的dp解决方案。
摘要由CSDN通过智能技术生成

今天主要刷了三个力扣题目,顺便记录一下昨天刷的
这几个题目还挺超出我能力范围的

1.最长增长子序列

参考:
https://leetcode.cn/problems/longest-increasing-subsequence/solutions/24173/zui-chang-shang-sheng-zi-xu-lie-dong-tai-gui-hua-2/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj
第一种方法就是两次循环遍历
核心思想是dp

class Solution {
        public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        int max = 1;
        Arrays.fill(dp,1);
        for (int i = 1; i < len; i++) {
            //看看前面比i小的数里面累计长度最大的   +1
            for (int j = 0; j < i; j++) {
                if(nums[i] > nums[j]){
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
            }
            max = Math.max(max,dp[i]);
        }
        return max;
    }
}

第二种方法有点类似于贪心
保存的数据比较特殊
数组record记录的分别为长度为1时最小的的数字 长度为2 时最小的数字 长度为n时最小的数字
从左向右遍历
如果大于长度为1的数字 那么这个字符串最小就是2了, 就像后遍历 如果小于这个数字 说明长度为1的数字 还能更小 更有利于让未来更长

 public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        int[] record = new int[len];
        record[0] =nums[0];
        int max = 1;
        for (int i = 1; i < len; i++) {
            boolean temp = true;
            for (int j = 0; j < max; j++) {
                if(nums[i] <= record[j]){
                    record[j] = nums[i];
                    temp = false;
                    break;
                }
            }
            if(temp){
                max++;
                record[max-1]=nums[i];
            }
        }
        return max;
    }

2.删除无效括号

参考:https://leetcode.cn/problems/remove-invalid-parentheses/solutions/1068652/gong-shui-san-xie-jiang-gua-hao-de-shi-f-asu8/?envType=featured-list&envId=2cktkvj?envType=featured-list&envId=2cktkvj
这个主要涉及到以下几个问题
1.最少删除几个左括号 和 右括号?

        for(char c:s.toCharArray()){
            if(c=='('){
                l++;
            }else if(c==')'){
                if(l != 0) l--;
                else r++;
            }
        }

2.在回溯过程中 右括号数目不能超过左括号数目 可以进行剪枝
当然左括号数目也不能超过最大的max
代码如下

class Solution {
    Set<String> set = new HashSet<>();
    int n, max, len;
    String s;
    public List<String> removeInvalidParentheses(String _s) {
        s = _s;
        n = s.length();
        int l = 0, r = 0;
        //真正合理的方式去计算削减左括号和右括号的数量
        for(char c:s.toCharArray()){
            if(c=='('){
                l++;
            }else if(c==')'){
                if(l != 0) l--;
                else r++;
            }
        }
        //最终的长度
        len = n-l-r;
       //这里的目的是剪枝 value值不能小于0 不能大于max=min(c1,c2)
        int c1 = 0, c2 = 0;
        for(char c : s.toCharArray()){
            if(c == '(') c1++;
            else if(c==')') c2++;
        }

        max = Math.min(c1,c2);
        //第一个参数是遍历原字符串字符的位置
        //第二个参数是组成的新字符串
        //第三个和第四个是应该删除的左右字符数
        //第五个参数是value
        dfs(0,"",l,r,0);
        return new ArrayList<>(set);
    }
    void dfs(int u,String cur, int l, int r, int score){
        if(l < 0||r<0||score<0||score>max) return;
        if(l==0 && r== 0){
            if(cur.length() == len) set.add(cur);
        }
        if(u == n) return;
        char c = s.charAt(u);
        if(c == '('){
            dfs(u+1,cur+String.valueOf(c), l, r, score+1);
            dfs(u+1,cur, l -1,r,score);
        }else if(c == ')'){
            dfs(u+1,cur+String.valueOf(c), l, r, score-1);
            dfs(u+1, cur ,l, r-1, score);
        }else{
            dfs(u+1, cur + String.valueOf(c),l,r,score);
        }
    }
}

3.买卖股票的最佳时机含冷冻期

这类问题都是通过状态向量机递得到的dp递推式
主要参考:https://www.bilibili.com/video/BV1ho4y1W7QK/?spm_id_from=333.337.search-card.all.click&vd_source=b81ab5eddf51d16c41cb0a31aeb9241a
dp主要维护两个状态 持有股票和未持有股票 max一定是未持有股票的
冷冻期主要体现在dp时 持有股票状态只能来源于前面隔一天的未持有股票状态

代码如下:

class Solution {
    public int maxProfit(int[] prices) {
        int len = prices.length;
        int[][] dp = new int[len+2][2];
        dp[1][1] = Integer.MIN_VALUE;
        for (int i = 0; i < len; i++) {
            dp[i+2][0] = Math.max(dp[i+1][0],dp[i+1][1] + prices[i]);
            dp[i+2][1] = Math.max(dp[i+1][1],dp[i][0] - prices[i]);

        }
        return dp[len+1][0];
    }
}

4.戳气球

也是一个dp问题
首先转化问题为戳 i 到 j 之间的气球的最大值 不包括i j
那么就可以遍历 i 到j 设定为 k
dp[i][j]就是所有 dp[i][k]+dp[k][j]+score[i]*score[j]*score[k]里面的最大值
score是对nums的扩展了头1 和 尾1
代码为

public int maxCoins(int[] nums) {
        int len = nums.length;
        int[] score = new int[len+2];
        score[0] = score[len+1] = 1;
        for (int i = 0; i < len; i++) {
            score[i+1] = nums[i];
        }
        int[][] dp = new int[len+2][len+2];
        for (int i = len; i >= 0 ; i--) {
            for (int j = i+1; j < len + 2; j++) {
                for (int k = i+1; k < j ; k++) {
                    dp[i][j] = Math.max(dp[i][j],dp[i][k] + dp[k][j] + score[i]*score[j]*score[k]);
                }
            }
        }
        return dp[0][len+1];
    }
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值