leetcode-dp

时间:2019-12-12
本文章向大家介绍leetcode-dp,主要包括leetcode-dp使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

参考文章

https://blog.csdn.net/u013309870/article/details/75193592
https://blog.csdn.net/baidu_28312631/article/details/47418773

动态规划

凡是可以大事化小的都可以用动态规划
一般解题步骤:找出最优子结构,找到状态转移方程,找到边界值

动态规划和贪心算法的区别

https://blog.csdn.net/weixin_39332529/article/details/89440114
最大的区别:贪心是通过局部最优解推导全局最优解
          dp是通过所有的最优解推导全局最优解
所以贪心算法推到的全局最优解未必正确

dp常见题目

第一道题目展示dp的优点,将阶时间复杂度
import java.util.HashMap;
import java.util.Map;

/**
 * You are climbing a stair case. It takes n steps to reach to the top.
 * 
 * Each time you can either climb 1 or 2 steps. In how many distinct ways can
 * you climb to the top?
 * 
 * Note: Given n will be a positive integer.
 * 
 * Example 1:
 * 
 * Input: 2 Output: 2 Explanation: There are two ways to climb to the top. 1. 1
 * step + 1 step 2. 2 steps Example 2:
 * 
 * Input: 3 Output: 3 Explanation: There are three ways to climb to the top. 1.
 * 1 step + 1 step + 1 step 2. 1 step + 2 steps 3. 2 steps + 1 step
 *
 */

public class Lc70 {
    /*
     * 递归: fn=fn-1+fn-2; f1=1 f2=2
     */

    public static int climbStairs(int n{
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 2;
        }
        return climbStairs(n - 1) + climbStairs(n - 2);
    }

    /*
     * 递归优化 备忘录
     */

    public static int climbStairs1(int n{
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 2;
        }
        Map<Integer, Integer> map = new HashMap<>();
        if (map.containsKey(n)) {
            return map.get(n);
        } else {
            int value = climbStairs1(n - 1) + climbStairs1(n - 2);
            map.put(n, value);
            return value;
        }

    }

    /**
     * 动态规划
     * 
     * 最优子结构:最后一步到顶点的步长? 状态转移方程: 若最后一步走一步,之前到最后一步为x种,若最后一步走俩步,则到最后一步有y中,那么到最后顶点为 x+y
     * 边界:f1=1; f2=2;
     * 
     * @param n
     * @return
     */

    public static int climbStairs2(int n{
        if (n == 1) {
            return 1;
        }
        if (n == 2) {
            return 2;
        }
        int a = 1;// ’走台阶1
        int b = 2;// ‘走台阶2

        for (int i = 3; i <= n; i++) {
            int temp = a + b;// 走当前台阶等于上一次加上上一次
            a = b;
            b = temp;
        }
        return b;
    }

    public static void main(String[] args{
        System.out.println(climbStairs(10));
        System.out.println(climbStairs1(10));
        System.out.println(climbStairs2(10));
    }
}
之后的题目展示dp常见的类型
import java.util.Arrays;

/**
 * Perfect Squares
 *
 */

public class Lc279 {
    /**
     * dp 最优子结构:完全平方数个数等于 非完全平方数 + 1(完全平方数) 状态转移方程:dp[n] =
     * min(dp[a-x*x]+1,dp(a+x*x)) 边界值 所有的平方值为1
     */

    public static int numSquares(int n) {
        int[] dp = new int[n + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        for (int i = 0; i * i <= n; i++) {
            dp[i * i] = 1;
        }
        for (int i = 0; i <= n; i++) {
            for (int j = 0; i + j * j <= n; j++) {
                dp[i + j * j] = Math.min(dp[i + j * j], dp[i] + 1);
            }
        }
        return dp[n];
    }

    public static void main(String[] args) {
        System.out.println(numSquares(12));
    }
}


import java.util.ArrayList;
import java.util.List;

/**
 * 问题: Given a non-empty string s and a dictionary wordDict containing a list of
 * non-empty words, determine if s can be segmented into a space-separated
 * sequence of one or more dictionary words.
 *
 */

public class Lc139 {
    /**
     * dp 最优子结构:若0到i截取的串可以匹配,若i到末尾也可以匹配则证明可以被串都匹配;
     * 
     * 状态转移方程:dp[i] = true
     * 
     * dp[j]= true dp[0] = true
     */

    public static boolean wordBreak(String s, List<String> wordDict) {
        int len = s.length();
        boolean[] dp = new boolean[len + 1];
        dp[0] = true;
        for (int i = 1; i <= len; i++) {
            for (int j = i - 1; j >= 0 && !dp[i]; j--) {
                String str = s.substring(j, i);
                dp[i] = dp[j] && wordDict.contains(str);
            }
        }
        return dp[len];

    }

    public static void main(String[] args) {
        String s = "leetcode";
        String s1 = "leet";
        String s2 = "code";
        List<String> wordDict = new ArrayList<String>();
        wordDict.add(s1);
        wordDict.add(s2);
        System.out.println(wordBreak(s, wordDict));
    }
}


这是dp找最大路径的模型
/**
 * 数字三角形,求最大路径和
 *
 */

public class LcMaxSum {
    public static int maxSum(int[][] array) {
        if (array == null) {
            return 0;
        }
        int row = array.length;

        int dp[] = array[row - 1];

        for (int i = row - 2; i >= 0; i--) {
            for (int j = 0; j < array[i].length; j++) {
                dp[j] = Math.max(array[i][j] + dp[j], array[i][j] + dp[j + 1]);
            }
        }
        return dp[0];
    }

    public static void main(String[] args) {
        int[][] array = { { 1 }, { 23 }, { 456 } };
        System.out.println(maxSum(array));
    }
}

/**
 * You are a professional robber planning to rob houses along a street. Each
 * house has a certain amount of money stashed, the only constraint stopping you
 * from robbing each of them is that adjacent houses have security system
 * connected and it will automatically contact the police if two adjacent houses
 * were broken into on the same night.
 * 
 * Given a list of non-negative integers representing the amount of money of
 * each house, determine the maximum amount of money you can rob tonight without
 * alerting the police.
 */

public class Lc198 {
    /*
     * 若dp[i]表示为当前最大值 则对于某个位置i ,存在取和不取,即dp[i-2]+num[i],dp[i-1]
     * 则状态转移方程max(dp[i-2]+num[i],dp[i-1])
     */

    public static int rob(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int dp[] = new int[nums.length];
        if (nums.length >= 1) {
            dp[0] = nums[0];
        }
        if (nums.length >= 2) {
            dp[1] = Math.max(nums[0], nums[1]);
        }
        if (nums.length >= 3) {
            for (int i = 2; i < nums.length; i++) {
                dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
            }
        }

        return dp[nums.length - 1];

    }

    public static void main(String[] args) {
        int[] nums = { 2112 };
        System.out.println(rob(nums));
    }
}

原文地址:https://www.cnblogs.com/xiaoshahai/p/12023454.html