美文网首页
动态规划

动态规划

作者: 专职掏大粪 | 来源:发表于2020-06-25 21:05 被阅读0次

1. 零钱兑换

  1. 零钱兑换 (Medium)

力扣

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

输入: coins = [2], amount = 3
输出: -1

题目描述:给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

时间复杂度:O(Sn),其中 SS 是金额,nn 是面额数。我们一共需要计算 O(S) 个状态,SS 为题目所给的总金额。对于每个状态,每次需要枚举 nn 个面额来转移状态,所以一共需要 O(Sn) 的时间复杂度。
空间复杂度:O(S)。DP 数组需要开长度为总金额 SS 的空间。

 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 coin : coins){
                 if(!(coin > i)){
                     dp[i] = Math.min(dp[i],dp[i-coin]+1);
                 }
             }
             
         }
         return dp[amount] == amount+1 ? -1 : dp[amount];
    }

2. 最长上升子序列

  1. 最长上升子序列

力扣

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

题目描述:给定一个无序的整数数组,找到其中最长上升子序列的长度。

时间复杂度:时间复杂度 O(N^2)

    public int lengthOfLIS(int[] nums) {
        int[] dp = new int [nums.length];
        Arrays.fill(dp,1);
        if(nums.length==0){
            return 0 ;
        }

        for(int i =0; i < nums.length; i++){
            for(int j=0; j< i; j++){
                if(nums[i] > nums[j]){
                    dp[i] = Math.max(dp[i],dp[j]+1);
                }
            }
        
        }
        int max = 1;
        for(int num : dp){
            max = Math.max(max, num);
        }
        return max;

    }

3. 最大子序和

  1. 最大子序和

力扣

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

题目描述:给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和

时间复杂度:时间复杂度是 O(N),空间复杂度也是 O(N)

       public int maxSubArray(int[] nums) {
        int dp[] = new int[nums.length];
        dp[0] = nums[0];
        for(int i =1; i< nums.length; i++){
            dp[i] = Math.max(nums[i],dp[i-1]+nums[i]);
        }
        int sum=Integer.MIN_VALUE;
        for(int num :dp){
            sum = Math.max(sum,num);
        }
        return sum;
    }

4. 分割等和子集

  1. 分割等和子集

力扣

输入: [1, 5, 11, 5]

输出: true

解释: 数组可以分割成 [1, 5, 5] 和 [11].


输入: [1, 2, 3, 5]

输出: false

解释: 数组不能分割成两个元素和相等的子集.

题目描述:给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

注意:

每个数组中的元素不会超过 100
数组的大小不会超过 200

时间复杂度:时间复杂度是 O(N),空间复杂度也是 O(N)

      public boolean canPartition(int[] nums) {
        int sum = 0;
        for( int num :nums){
            sum+=num;
        }
        int mid = sum/2;
            if (sum % 2 != 0) return false;

        boolean dp[][] = new boolean[nums.length+1][mid+1];
         for (int i = 0; i <= nums.length; i++)
            dp[i][0] = true;

        for(int i =1;i<=nums.length;i++){
            for(int j=1;j<=mid;j++){
                if(j<nums[i-1]){
                    dp[i][j]=dp[i-1][j];
                }else{
                    dp[i][j] = dp[i-1][j] | dp[i-1][j-nums[i-1]];
                }
            }
        }

        return dp[nums.length][mid];
    }

5. 零钱兑换 II

  1. 零钱兑换 II

力扣

输入: amount = 5, coins = [1, 2, 5]
输出: 4
解释: 有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

输入: amount = 3, coins = [2]
输出: 0
解释: 只用面额2的硬币不能凑成总金额3。

题目描述:给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

时间复杂度:时间复杂度是 O(N),空间复杂度也是 O(N)

    public int change(int amount, int[] coins) {
        int[][] dp = new int[coins.length+1][amount+1];
        for(int i =0;i<=coins.length;i++){
            dp[i][0]=1;
        }

        for(int i = 1;i<=coins.length;i++){
            for(int j = 1;j <= amount; j++){
                if(j>=coins[i-1]){
                    dp[i][j] = dp[i-1][j]+dp[i][j-coins[i-1]];
                }else{
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return dp[coins.length][amount];
    }

6. 编辑距离

  1. 编辑距离

力扣

输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

题目描述:给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符

时间复杂度:时间复杂度是 O(N),空间复杂度也是 O(N)

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

    }

7. 最长公共子序列

  1. 最长公共子序列

力扣

输入:text1 = "abcde", text2 = "ace" 
输出:3  
解释:最长公共子序列是 "ace",它的长度为 3。

输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc",它的长度为 3。

题目描述:给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。

若这两个字符串没有公共子序列,则返回 0。

        public int longestCommonSubsequence(String text1, String text2) {
        int[][] dp = new int[text1.length()+1][text2.length()+1];
       
       for(int i =1;i <=text1.length();i++){
           for(int j =1;j <=text2.length();j++){
               if(text1.charAt(i-1)==text2.charAt(j-1)){
                   dp[i][j] = dp[i-1][j-1]+1;
               }else{
                   dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
               }
           }
       }
       return dp[text1.length()][text2.length()];
    }

8. 最长回文子序列

  1. 最长回文子序列

力扣

示例 1:
输入:

"bbbab"

输出:


一个可能的最长回文子序列为 "bbbb"。

示例 2:
输入:

"cbbd"

输出:


一个可能的最长回文子序列为 "bb"。


题目描述:给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。

           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  i=n-1;i>=0;i--){
            for(int j =i+1;j<n;j++){
                if(s.charAt(i)==s.charAt(j)){
                    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][s.length()-1];
}

9. 最长回文子串

  1. 最长回文子串

力扣

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

题目描述:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

时间复杂度:O(n^2),其中 n 是字符串的长度。长度为 111 和 222 的回文中心分别有 n 和 n−1个,每个回文中心最多会向外扩展 O(n) 次。

空间复杂度:O(1)。

         public String longestPalindrome(String s) {
    if(s.length()<2){
            return s;
        }

        String maxStr = "";
        for(int i =0; i < s.length(); i++){
            String odd = help(s,i,i);
            String even = help(s,i,i+1);
            maxStr = odd.length()>maxStr.length()?odd:maxStr;
            maxStr = even.length()>maxStr.length()?even:maxStr;
        }
        return maxStr;
        }
    
        String help(String s, int i, int j){
            while(i>=0&&j<s.length()&&s.charAt(i)==s.charAt(j)){
                    i--;
                    j++;
                
            }
            return s.substring(i+1,i+1+j-i-1);
        }

相关文章

网友评论

      本文标题:动态规划

      本文链接:https://www.haomeiwen.com/subject/jghsohtx.html