DynamicProgramming

目录

连续子数组的最大和

 最长公共子串

最长回文子串

最长递增子序列

买卖股票的最好时机

字符串的排列

矩阵的最小路径和

最小编辑代价

求路径

最长公共子序列-II

01背包

最长公共子序列


连续子数组的最大和

输入一个长度为n的整型数组a,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为 O(n).

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int res = array[0];
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            max = Math.max(max + array[i], array[i]);
            res = Math.max(max, res);
        }
        return res;
    }
}

 最长公共子串

给定两个字符串str1和str2,输出两个字符串的最长公共子串

题目保证str1和str2的最长公共子串存在且唯一。

import java.util.*;
public class Solution {
    /**
     * longest common substring
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String str1, String str2) {
        // write code here
        int[][] lcs = new int[str1.length() + 1][str2.length() + 1];
        int max = 0;
        int index = 0;
        for (int i = 1; i <= str1.length(); i++) {
            for (int j = 1; j <= str2.length(); j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    lcs[i][j] = lcs[i - 1][j - 1] + 1;
                    if (lcs[i][j] > max) {
                        max = lcs[i][j];
                        index = i;
                    }
                }
            }
        }
        return str1.substring(index - max, index);
    }
}

最长回文子串

对于一个字符串(仅包含小写英文字母),请设计一个高效算法,计算其中最长回文子串的长度。

给定字符串 以及它的长度 ,请返回最长回文子串的长度。

import java.util.*;
public class Solution {
    //helper function
    public boolean isPalindrome(String A, int n) {
        int k = n / 2;
        for (int i = 0; i < k; ++i) {
            if (A.charAt(i) != A.charAt(n - 1 - i)) {
                return false;
            }
        }
        return true;
    }
    public int getLongestPalindrome(String A, int n) {
        // write code here
        int maxlen  = 0;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j <= n ; j++) {
                if (isPalindrome(A.substring(i, j), j - i)) {
                    if (j - i > maxlen) {
                        maxlen = j - i;
                    }
                }
            }
        }
        return maxlen;
    }
}

最长递增子序列

给定数组 arr ,设长度为 n ,输出 arr 的最长递增子序列。(如果有多个答案,请输出其中 按数值(注:区别于按单个字符的ASCII码值)进行比较的 字典序最小的那个)

    public int lengthOfLIS(int[] nums) 
	{
		// Base case
		if(nums.length <= 1) 
			return nums.length;

		// This will be our array to track longest sequence length
		int T[] = new int[nums.length];

		// Fill each position with value 1 in the array
		for(int i=0; i < nums.length; i++)
			T[i] = 1;


		// Mark one pointer at i. For each i, start from j=0.
		for(int i=1; i < nums.length; i++)
		{
			for(int j=0; j < i; j++)
			{
				// It means next number contributes to increasing sequence.
				if(nums[j] < nums[i])
				{
					// But increase the value only if it results in a larger value of the sequence than T[i]
					// It is possible that T[i] already has larger value from some previous j'th iteration
					if(T[j] + 1 > T[i])
					{
						T[i] = T[j] + 1;
					}
				}
			}
		}

		// Find the maximum length from the array that we just generated 
		int longest = 0;
		for(int i=0; i < T.length; i++)
			longest = Math.max(longest, T[i]);

		return longest;
	}

买卖股票的最好时机

假设你有一个数组,其中第 i 个元素是股票在第i天的价格。
你可以买入一次股票和卖出一次股票(并非每天都可以买入或卖出一次,总共只能买入和卖出一次),问能获得的最大收益是多少。

import java.util.*;
public class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int max=0;
        int min=prices[0];
        for(int i=0;i<prices.length;i++){
            min = Math.min(min,prices[i]);
            max=Math.max(max,prices[i]-min);
        }
        return max;
    }
}

字符串的排列

输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。

例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。

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

public class Solution {
    public static void main(String[] args) {
        Solution p = new Solution();
        System.out.println(p.Permutation("abc").toString());
    }

    public ArrayList<String> Permutation(String str) {
        List<String> res = new ArrayList<>();
        if (str != null && str.length() > 0) {
            PermutationHelper(str.toCharArray(), 0, res);
            Collections.sort(res);
        }
        return (ArrayList)res;
    }

    public void PermutationHelper(char[] cs, int i, List<String> list) {
        if (i == cs.length - 1) {
            String val = String.valueOf(cs);
            if (!list.contains(val)) 
                list.add(val);
        } else {
            for (int j = i; j < cs.length; j++) {
                swap(cs, i, j);
                PermutationHelper(cs, i+1, list);
                swap(cs, i, j);
            }
        }
    }

    public void swap(char[] cs, int i, int j) {
        char temp = cs[i];
        cs[i] = cs[j];
        cs[j] = temp;
    }
}

矩阵的最小路径和

给定一个 n * m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。

import java.util.*;
import java.util.*;

public class Solution {
    /**
     * 
     * @param matrix int整型二维数组 the matrix
     * @return int整型
     */
    public int minPathSum (int[][] matrix) {
        // write code here
        int m=matrix.length;
        int n=matrix[0].length;
        int[][] dp=new int[m][n];
        dp[0][0]=matrix[0][0];
        //第一行
        for(int i=1;i<n;i++){
            dp[0][i]=dp[0][i-1]+matrix[0][i];
        }
        //第一列
        for(int i=1;i<m;i++){
            dp[i][0]=dp[i-1][0]+matrix[i][0];
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j]=Math.min(dp[i][j-1],dp[i-1][j])+matrix[i][j];
            }
        }
        return dp[m-1][n-1];
    }
}

最小编辑代价

给定两个字符串str1和str2,再给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,请输出将str1编辑成str2的最小代价。

import java.util.*;
public class Solution {
    /**
     * min edit cost
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @param ic int整型 insert cost
     * @param dc int整型 delete cost
     * @param rc int整型 replace cost
     * @return int整型
     */
    public int minEditCost (String str1, String str2, int ic, int dc, int rc) {
    // 如果其中一个为空
    if (str1.length() == 0) return str2.length() * ic;
    if (str2.length() == 0) return str1.length() * dc;
    int n1 = str1.length(), n2 = str2.length();
    // dp[0][0] 表示空字符串变成空字符串的代价(0),可以简化操作
    int[][] dp = new int[n1 + 1][n2 + 1];
    // 初始化:
    // 1、由 str1 变成空字符串的代价
    for (int i = 0; i <= n1; i++) dp[i][0] = i * dc;
    // 2、由空字符串变成 str2 的代价
    for (int i = 0; i <= n2; i++) dp[0][i] = i * ic;
    // 状态转移
    for (int i = 1; i <= n1; i++) {
        for (int j = 1; j <= n2; j++) {
            if (str1.charAt(i - 1) == str2.charAt(j - 1)) dp[i][j] = dp[i-1][j-1];
            else dp[i][j] = Math.min(dp[i-1][j] + dc, Math.min(dp[i][j-1] + ic, dp[i-1][j-1] + rc));
        }
    }
    return dp[n1][n2];
}
}

求路径

一个机器人在m×n大小的地图的左上角(起点)。

机器人每次可以向下或向右移动。机器人要到达地图的右下角(终点)。

可以有多少种不同的路径从起点走到终点?

public class Solution {
    public int uniquePaths(int m, int n) {
		int[][] dp = new int[m][n];
		for (int i = 0; i < m; i ++)
			dp[i][0] = 1;
		for (int i = 0; i < n; i ++)
			dp[0][i] = 1;
		for (int i = 1; i < m; i ++)
			for (int j = 1; j < n; j ++)
				dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
		return dp[m - 1][n - 1];
	}
}

最长公共子序列-II

给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列

class Solution {
public:
    string LCS(string s1, string s2) {
        // write code here
        string dp[s1.size()+1][s2.size()+1];
        for(int i=0;i<=s1.size();i++)
            dp[i][0] = "";
        for(int i=0;i<=s2.size();i++)
            dp[0][i] = "";
        for(int i=1;i<=s1.size();i++){
            for(int j=1;j<=s2.size();j++){
                if(s1[i-1]==s2[j-1]) dp[i][j] = dp[i-1][j-1]+s1[i-1];
                else{
                    dp[i][j] = dp[i-1][j].size()>dp[i][j-1].size()?dp[i-1][j]:dp[i][j-1];
                }
            }
        }
        return dp[s1.size()][s2.size()]==""?"-1":dp[s1.size()][s2.size()];
    }
};

01背包

已知一个背包最多能容纳体积之和为v的物品

现有 n 个物品,第 i 个物品的体积为 vi , 重量为 wi

求当前背包最多能装多大重量的物品?

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 计算01背包问题的结果
     * @param V int整型 背包的体积
     * @param n int整型 物品的个数
     * @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
     * @return int整型
     */
    public int knapsack2(int V, int n, int[][] vw) {
        if (V <= 0 || n <= 0 || vw.length != n) {
            return -1;
        }
        int[][] w = new int[n + 1][V + 1];
        for (int i = n - 1; i >= 0; --i) {
            for (int j = 1; j <= V; ++j) {
                if (vw[i][0] <= j) {
                    w[i][j] = Math.max(w[i + 1][j - vw[i][0]] + vw[i][1], w[i + 1][j]);
                } else {
                    w[i][j] = w[i + 1][j];
                }
            }
        }
        return w[0][V];
    }

    public int knapsack(int V, int n, int[][] vw) {
        if (V <= 0 || n <= 0 || vw.length != n) {
            return -1;
        }
        int[] w = new int[V + 1];
        for (int i = 0; i < n; ++i) {
            for (int j = V; j >= 1; --j) {
                if (vw[i][0] <= j) {
                    w[j] = Math.max(w[j - vw[i][0]] + vw[i][1], w[j]);
                }
            }
        }
        return w[V];
    }
}

最长公共子序列

给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则输出-1

import java.util.Scanner;

public class Main {

    private String lcs(String s, String t) {
        int m = s.length(), n = t.length();
        int[][] opt = new int[m+1][n+1];
        for (int i = m-1; i >= 0; i--) {
            for (int j = n-1; j>= 0; j--) {
                if (s.charAt(i) == t.charAt(j))
                    opt[i][j] = opt[i+1][j+1] + 1;
                else
                    opt[i][j] = Math.max(opt[i+1][j], opt[i][j+1]);
            }
        }

        StringBuilder result = new StringBuilder();
        int i = 0, j = 0;
        while (i < m && j < n) {
            if (s.charAt(i) == t.charAt(j)) {
                result.append(s.charAt(i));
                i++;
                j++;
            }
            else if (opt[i+1][j] >= opt[i][j+1]) i++;
            else                                 j++;
        }
        return result.toString();
    }
    public Main() {
        Scanner in = new Scanner(System.in);
        String lcs = lcs(in.next(), in.next());
        System.out.println(lcs);
    }

    public static void main(String[] args) {
        Main solution = new Main();
    }
}

子数组最大乘积

给定一个double类型的数组arr,其中的元素可正可负可0,返回连续子数组累乘的最大乘积。

public class Solution {
    //连续子数组乘积的最大值
    public double maxProduct(double[] arr) {
        double min=arr[0];
        double max=arr[0];
        double res=arr[0];
        //最大值有可能出现在之前的最小值*当前值,比如最小值为-100,arr[i]<0,同理,最小值也可能出现在之前的最大值,所以每次比较三个值
        for(int i=1;i<arr.length;i++){
            double last_max=max,last_min=min;
            min=Math.min(arr[i],Math.min(arr[i]*last_min,arr[i]*last_max));
            max=Math.max(arr[i],Math.max(arr[i]*last_min,arr[i]*last_max));
            res=Math.max(max,res);
        }
        return res;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值