Letcode-Top 100动态规划

这篇博客探讨了多种使用动态规划解决编程问题的方法,包括寻找最大子数组和、爬楼梯问题、计算比特位计数、买卖股票的最佳时机以及括号生成。博主详细介绍了每种问题的动态规划解决方案,并提供了简洁的代码实现。此外,还提到了贪心算法在跳跃游戏中找到可行路径的应用,以及零钱兑换问题的动态规划求解。这些例子展示了动态规划如何通过优化计算过程提高效率。
摘要由CSDN通过智能技术生成

1.简单-最大子数组和

1.动态规划

class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0];
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for(int i=1;i<nums.length;i++){
            if(dp[i-1]>0){
                dp[i]= dp[i-1] + nums[i];
            }else{
                dp[i]= nums[i];
            }

            if(dp[i]>max){
                max = dp[i];
            }
        }
        return max;
    }
}
// 首先是动态规划方程

//dp[i] 
// 前i-1位的最大值


//dp[i]>0
//dp[i-1]>0

//      f(n-1)+nums[i]                         f(n-1)>0
//f(n) 
//       nums[i]                          f(n-1)<0

2.简单-爬楼梯

1.动态规划

class Solution {
    public int climbStairs(int n) {

       int[] dp = new int[n+1];

        if(n==1){
            return 1;
        }

        dp[1]=1;

        if(n==2){
            return 2;
        }
        dp[2]=2;


        for(int i=3;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }

        return dp[n];
    }
}

// 第一步:首先动态规划方程
// 
// f(1)=1;
// f(2)=2;
// f(n) = f(n-1) + f(n-2)



3.简单-比特位计数

1.常规方法
在这里插入图片描述

class Solution {
    public int[] countBits(int n) {
        int[] totalNumber = new int[n+1];
        for(int i=1;i<=n;i++){
            totalNumber[i] = countNumber(i);
        }
        return totalNumber;
    }

    public int countNumber(int n){
    int one = 0;
     // 对每个数字判断位数
     while(n>0){
          // 数组换位 
          n= n&(n-1); 
          one++;
     }   
     return one;
    }

}

2.动态规划
在这里插入图片描述

class Solution {
    public int[] countBits(int n) {
        int[] dp = new int[n+1];
        int highBit = 0; 
        for(int i=1;i<dp.length;i++){
            if((i&(i-1))==0){
                highBit = i;
            }
            dp[i] = dp[i-highBit]+1;
        }
        return dp;

    }
}

4.简单-买卖股票的最佳时机

1.暴力破解的方式
在这里插入图片描述

public class Solution {
    public int maxProfit(int[] prices) {
        int maxprofit = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                int profit = prices[j] - prices[i];
                if (profit > maxprofit) {
                    maxprofit = profit;
                }
            }
        }
        return maxprofit;
    }
}

2.动态规划方式
在这里插入图片描述

class Solution {
    public int maxProfit(int[] prices) {
        // 买卖股票的最佳时机
        int[] dp = new int[prices.length];
        dp[0] = prices[0];
        int maxProfit = 0;

         //dp[i]表示截止到i,价格的最低点是多少   dp[i]=min(dp[i-1],nums[i])
        for(int i=1;i<prices.length;i++){
            dp[i] = dp[i-1]>prices[i] ?prices[i]:dp[i-1];
            maxProfit = prices[i]-dp[i-1]>maxProfit?prices[i]-dp[i-1]:maxProfit;
        }

        return maxProfit;
    }
}

5.中等-括号生成

1.动态规划
简单来说,在求N个括号的排列组合时,把第N种情况(也就是N个括号排列组合)视为单独拿一个括号E出来,剩下的N-1个括号分为两部分,P个括号和Q个括号,P+Q=N-1,然后这两部分分别处于括号E内和括号E的右边,各自进行括号的排列组合。由于我们是一步步计算得到N个括号的情况的,所以小于等于N-1个括号的排列组合方式我们是已知的(用合适的数据结构存储,方便后续调用,且在存储时可利用特定数据结构实现题目某些要求,如排序,去重等),且P+Q=N-1,P和Q是小于等于N-1的,所以我们能直接得到P个和Q个括号的情况,进而得到N个括号的结果!

楼主的算法思想很巧妙,赞一个~这个算法主要的基点就是将排列组合的情况分为了括号内和括号外这两种情况,且仅存在两种情况!至于为什么,原因在于楼主的算法的前提是单独拿出来的括号E的左边在N个括号所有排列组合情况中都是处于最左边,所以不存在括号位于括号E的左边的情况。因此,N-1个括号(拿出了括号E)仅可能分布于括号E内和括号E外,分为两种子情况讨论! 这种思想还可以应用于其他类似的题的求解中,即怎样合理高效的利用前面步骤的计算结果得出当前步骤结果,从而得出最终结果。

class Solution {
    public List<String> generateParenthesis(int n) {
        ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
        if(n == 0){
            return result.get(0);
        }
        ArrayList<String> List0 = new ArrayList<String>();
        List0.add("");
        result.add(List0);

        ArrayList<String> list1 = new ArrayList<String>();
        list1.add("()");
        result.add(list1);

        for(int i = 2;i<=n;i++){
            ArrayList<String> temp = new ArrayList<String>();
            for(int j =0;j<i;j++){
                List<String> str1 = result.get(j);
                List<String> str2 = result.get(i-1-j);
                for(String s1:str1){
                    for(String s2:str2){
                        String e1 = "(" + s1 + ")" +s2;
                        temp.add(e1);
                    }

                }
            }
            result.add(temp);
        }
        return  result.get(n);
    }
}

// i+j = i-1

2.DFS

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> generateParenthesis(int n) {
        dfs(n, n, "");
        return res;
    }

    private void dfs(int left, int right, String curStr) {
        if (left == 0 && right == 0) { // 左右括号都不剩余了,递归终止
            res.add(curStr);
            return;
        }

        if (left > 0) { // 如果左括号还剩余的话,可以拼接左括号
            dfs(left - 1, right, curStr + "(");
        }
        if (right > left) { // 如果右括号剩余多于左括号剩余的话,可以拼接右括号
            dfs(left, right - 1, curStr + ")");
        }
    }

}

6.中等-跳跃游戏

1.思路一:用一个动态规划数组,存储所有可能到达的路径,然后遍历

class Solution {
    public static boolean canJump(int[] nums) {
        int length = nums.length;
        if(length==1){
            return true;
        }

        boolean[] flag = new boolean[nums.length];
        flag[0] = true;
        //
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<=i+nums[i]&&j<nums.length;j++){
                flag[j]=true;
            }
        }

       for(int i=0;i<nums.length;i++){
         if(!flag[i]){
             return false;
         }
       }
       return true;

    }
}

2.思路二:贪心算法
在这里插入图片描述

class Solution {
    public boolean canJump(int[] nums) {
        int rightMax = 0;
    
        for(int i=0;i<nums.length;i++){
            // 边界终止条件
            if(i<=rightMax){
                // 不断更新最大的右边界
                rightMax = Math.max(rightMax,nums[i]+i);
                if(rightMax>=nums.length-1){
                    return true;
                }
            }
            
        }
        return false;
    }
}

7.中等-零钱兑换

1.动态规划
在这里插入图片描述

class Solution {
    public int coinChange(int[] coins, int amount) {
        // 首先 定义动态规划数组
        int[] dp = new int[amount+1];
        Arrays.fill(dp,amount+1);
        dp[0] = 0;
        for(int i=1;i<=amount;i++){
            for(int j=0;j<coins.length;j++){
                if(coins[j]<=i){
                    dp[i] = Math.min(dp[i],dp[i-coins[j]]+1);
                }
            }
        }

        return dp[amount]==amount+1?-1:dp[amount];
    }
}




8.最长有效括号

在这里插入图片描述
1.动态规划
在这里插入图片描述
在这里插入图片描述

class Solution {
    public int longestValidParentheses(String s) {
        int maxans = 0;
        int[] dp = new int[s.length()];
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == ')') {
                if (s.charAt(i - 1) == '(') {
                    dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
                } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                    dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
                }
                maxans = Math.max(maxans, dp[i]);
            }
        }
        return maxans;
    }
}


2.栈
在这里插入图片描述

import java.util.Stack;
class Solution {
    public int longestValidParentheses(String s) {
        int maxans = 0;
        Stack<Integer> stack = new Stack<Integer>();
        stack.push(-1);

        for(int i =0;i<s.length();i++){
            if(s.charAt(i)=='('){
                stack.push(i);
            } else{
                stack.pop();
                if(stack.isEmpty()){
                    stack.push(i);
                }else{
                    maxans = Math.max(maxans,i-stack.peek());
                }
            }

        }

        return maxans;

    }
}```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值