测试开发备战秋招面试14-牛客刷题之动态规划

努力了那么多年,回头一望,几乎全是漫长的挫折和煎熬。对于大多数人的一生来说,顺风顺水只是偶尔,挫折、不堪、焦虑和迷茫才是主旋律。我们登上并非我们所选择的舞台,演出并非我们所选择的剧本。继续加油吧!

目录

1、斐波那契数列

2、跳台阶

3、最小花费爬楼梯

4、最长公共子序列(二)

5、 最长公共子串

6、不同路径的数目(一)

7、矩阵的最小路径和

8、把数字翻译成字符串

9、兑换零钱

10、最长上升子序列(一)

11、连续子数组的最大和

12、最长回文子串

13、数字字符串转化成IP地址

14、编辑距离(一)

15、 最长的括号子串

16、打家劫舍1

17、打家劫舍2

18、买卖股票的最好时机(一)

19、 买卖股票的最好时机(二)

20、买卖股票的最好时机(三)


1、斐波那契数列

题目链接:斐波那契数列_牛客题霸_牛客网

思路:f(n) = f(n-1) + f(n-2)

Java版:

public class Solution {
    public int Fibonacci(int n) {
        if(n==1 || n==2){
            return 1 ;
        }
        return Fibonacci(n-1) + Fibonacci(n-2) ;
    }
}

2、跳台阶

题目链接:跳台阶_牛客题霸_牛客网

思路:和斐波那契数列一样的思路,只不过出口不一样。

Java版:

public class Solution {
    public int jumpFloor(int target) {
        if(target==1 ){
            return 1 ;
        }
        if(target==2){
            return 2 ;
        }

        return jumpFloor(target-1) + jumpFloor(target-2) ;
    }
}
public class Solution {
    public int jumpFloor(int target) {
      int [] ans = new int [target] ;
      ans[0] = 1 ;
      if(ans.length > 1)
      ans[1] = 2 ;
      for(int i=2; i<ans.length; i++){
        ans[i] = ans[i-1] + ans[i-2]  ;
      }
      return ans[target-1] ;
    }
}

3、最小花费爬楼梯

题目链接:最小花费爬楼梯_牛客题霸_牛客网
思路:爬到当前楼梯的最小花费=min(上个楼梯的最小花费+费用,上上个楼梯的最小花费+费用)
Java版:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param cost int整型一维数组 
     * @return int整型
     */
    public int minCostClimbingStairs (int[] cost) {
        // write code here
        int [] dp = new int [cost.length+1] ;
        dp[0] = dp[1] = 0 ;
        for(int i=2; i<dp.length; i++){
            dp[i] = Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]) ;
        }
        return dp[cost.length] ;
    }
}

4、最长公共子序列(二)

题目链接:最长公共子序列(二)_牛客题霸_牛客网

思路:先求出最长公共子序列的长度然后从后到前找出最长公共子序列,最后翻转一下。

Java版:

import java.util.*;


public class Solution {
    /**
     * longest common subsequence
     * @param s1 string字符串 the string
     * @param s2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String s1, String s2) {
        // write code here
        int n = s1.length() + 1, m = s2.length() + 1 ;
        int [][] dp = new int [n][m] ;
        for(int i=1; i<n; i++){
            for(int j=1; j<m; j++){
                if(s1.charAt(i-1) == s2.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]) ;
                }
            }
        }
        StringBuilder sb = new StringBuilder("") ; 
        int l1 = s1.length(), l2 = s2.length() ;
        while(l1 > 0 && l2 > 0){
            if(s1.charAt(l1-1) == s2.charAt(l2-1)){
                sb.append(s1.charAt(l1-1)) ;
                l1 -- ;
                l2 -- ;
            }else{
                if(dp[l1-1][l2] > dp[l1][l2-1]){
                    l1 -- ;
                }else{
                    l2 -- ;
                }
            }
        }
        if(sb.length() == 0){
            return "-1" ;
        }
        return sb.reverse().toString() ;
    }
}

5、 最长公共子串

题目链接:最长公共子串_牛客题霸_牛客网

思路:求出最长公共字串的长度,并记录下标,然后直接截取字符串就可以。
Java版:
 

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 n = str1.length() + 1, m = str2.length() + 1 ;
        int [][] dp = new int [n][m] ;
        int max = 0, pos = 0 ;
        for(int i=1; i<n; i++){
            for(int j=1; j<m; j++){
                if(str1.charAt(i-1) == str2.charAt(j-1)){
                    dp[i][j] = dp[i-1][j-1] + 1 ;
                }else{
                    dp[i][j] = 0 ;
                }
                if(dp[i][j] > max){
                    max = dp[i][j] ;
                    pos = i - 1 ;
                }
            }
        }
        return str1.substring(pos-max+1, pos+1) ;
    }
}

6、不同路径的数目(一)

题目链接:不同路径的数目(一)_牛客题霸_牛客网

思路:dp[i][j] = dp[i-1][j] + dp[i][j-1]
Java版:

import java.util.*;


public class Solution {
    /**
     * 
     * @param m int整型 
     * @param n int整型 
     * @return int整型
     */
    public int uniquePaths (int m, int n) {
        // write code here
        int [][] dp = new int [m+1][n+1] ;
        for(int i=1; i<=m; i++){
            for(int j=1; j<=n; j++){
                if(i==1 || j==1){
                    dp[i][j] = 1 ;
                }else{
                    dp[i][j] = dp[i-1][j] +dp[i][j-1] ;
                }
            }
        }
        return dp[m][n] ;
    }
}

7、矩阵的最小路径和

题目链接:矩阵的最小路径和_牛客题霸_牛客网

思路:dp[i][j] = min(dp[i-1][j],dp[i][j-1])+matrix[i][j]

Java版:

import java.util.*;


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

8、把数字翻译成字符串

题目链接:把数字翻译成字符串_牛客题霸_牛客网

思路:凡是出现11-19,21-26的就有两种编码方式,其余的要么一种,要么0种。

Java版:

import java.util.*;


public class Solution {
    /**
     * 解码
     * @param nums string字符串 数字串
     * @return int整型
     */
    public int solve (String nums) {
        // write code here
        if(nums.equals("0")){
            return 0 ;
        }
        if(nums.equals("10") || nums.equals("20")){
            return 1 ;
        }
        for(int i=1; i<nums.length(); i++){
            if(nums.charAt(i) == '0'){
                if(nums.charAt(i-1) != '1' && nums.charAt(i-1) != '2'){
                    return 0 ;
                }
            }
        }
        int [] dp = new int [nums.length()+1];
        Arrays.fill(dp,1) ;
        for(int i=2; i<dp.length; i++){
            if((nums.charAt(i-2) == '1' && nums.charAt(i-1) != '0') || (nums.charAt(i-2)== '2' && nums.charAt(i-1) > '0' && nums.charAt(i-1) < '7')){
                dp[i] = dp[i-1]  + dp[i-2] ;
            }else{
                dp[i] = dp[i-1] ;
            }
        }
        return dp[nums.length()] ;
    }
}





9、兑换零钱

题目链接:兑换零钱(一)_牛客题霸_牛客网

思路:列举出1-aim的所有dp[i],递推公式:dp[i] = Math(dp[i], dp[j-arr[i]] + 1),时间复杂度O(n*aim)

Java版:

import java.util.*;


public class Solution {
    /**
     * 最少货币数
     * @param arr int整型一维数组 the array
     * @param aim int整型 the target
     * @return int整型
     */
    public int minMoney (int[] arr, int aim) {
        // write code here
        int [] dp = new int [aim+1] ;
       
         Arrays.fill(dp, aim+1) ;
         dp[0] = 0 ;
         //要列举所有的1-aim才行,并且每一个都要从所有的里面递推出最小的种类数目
        for(int j=1; j<=aim ; j++){
        for(int i=0; i<arr.length; i++){
            if(arr[i] <= j){
                dp[j] = Math.min(dp[j], dp[j - arr[i]] + 1) ;
            }
        }
        }
        int result = dp[aim] > aim ? -1 : dp[aim] ;
        return result ;
    }
}

10、最长上升子序列(一)

题目链接:最长上升子序列(一)_牛客题霸_牛客网

思路:dp[i]表示以i结尾的最长上升子序列的长度,双层循环,arr[i] > arr[j] && dp[i] < dp[j]+1时候更新dp[i].

Java版:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 给定数组的最长严格上升子序列的长度。
     * @param arr int整型一维数组 给定的数组
     * @return int整型
     */
    public int LIS (int[] arr) {
        // write code here
        int [] dp = new int [arr.length] ;
        if(arr.length == 0){
            return 0 ;
        }
        Arrays.fill(dp, 1) ;
        int max = 1 ;

        for(int i=1; i<arr.length; i++){
            for(int j=0; j<i; j++){
                if(arr[i] > arr[j] && dp[i] < dp[j]+1){
                    dp[i] = dp[j] + 1 ;
                }
                if(max < dp[i]){
                    max = dp[i] ;
                }
            }
        }
        return max ;
    }
}

11、连续子数组的最大和

题目链接:连续子数组的最大和_牛客题霸_牛客网

思路:之前累加的数字大于0,才允许累加当当前,否则继续从当前开始累加,累加过程中的最大值就是连续子数组的最大和。

Java版:

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
       //最好保证时间复杂度为O(n),空间复杂度为O(1)
       int sum = 0 ;
       int max = -100 ;

       for(int i=0; i<array.length; i++){
        if(sum + array[i] > array[i]){
            sum += array[i] ;
        }else{
            sum = array[i] ;
        }
        if(max < sum){
            max = sum ;
        }
       }
       return max ;
       
    }
}

12、最长回文子串

题目链接:最长回文子串_牛客题霸_牛客网

思路:dp[i][j]表示从i到j的最长回文字串,不过要以长度作为外层循环才行。

Java版:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param A string字符串 
     * @return int整型
     */
    public int getLongestPalindrome (String A) {
        // write code here
        int max = 0 ;
        int n = A.length() ;
        boolean [][] dp = new boolean [n][n] ;
        //dp[i][i+j]:i表示开始,j表示长度,从i到i+j的最长回文字串啊
        for(int j = 0; j<n; j++){
            for(int i=0; i+j<n; i++){
              if(j==0){
                dp[i][i+j] = true ;
              }else if(j==1){
                dp[i][i+j] = (A.charAt(i) == A.charAt(i+j))  ;
              }else{
                dp[i][i+j] = (A.charAt(i) == A.charAt(i+j) && dp[i+1][i+j-1]) ;
              }
              if(dp[i][i+j] && j+1>max){
                max = j + 1 ;
              }
            }
        }
        return max ;
    }
}

13、数字字符串转化成IP地址

题目链接:数字字符串转化成IP地址_牛客题霸_牛客网

思路:循环判断满足长度和ip地址要求的字符串加入集合即可。

Java版:

import java.util.*;


public class Solution {
    /**
     * 
     * @param s string字符串 
     * @return string字符串ArrayList
     */
    public ArrayList<String> restoreIpAddresses (String s) {
        // write code here
        ArrayList<String> list = new ArrayList<>() ;
        for(int i=1; i<=3; i++){
            for(int j=1; j<=3; j++){
                for(int k=1; k<=3; k++){
                    for(int l=1; l<=3; l++){
                        if(i+j+k+l==s.length()){
                            String s1 = s.substring(0,i) ;
                            String s2 = s.substring(i,i+j) ;
                            String s3 = s.substring(i+j, i+j+k) ;
                            String s4 = s.substring(i+j+k, i+j+k+l) ;
                            if(f(s1) && f(s2) && f(s3) && f(s4)){
                                String tmp = s1 + "." + s2 + "." + s3 + "." + s4 ;
                                list.add(tmp) ;
                            }
                        }
                    }
                }
            }
        }
        return list ;
    }
    public boolean f(String s){
        if(s.length() == 1){
            return true ;
        }else if(s.charAt(0) != '0' && Integer.parseInt(s) >= 10 && Integer.parseInt(s) <= 255){
            return true ;
        }
        return false ;
    }
}

14、编辑距离(一)

题目链接:编辑距离(一)_牛客题霸_牛客网

思路:dp[i][j]表示从开始到str1[i],str2[j]的最小操作次数。

Java版:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str1 string字符串 
     * @param str2 string字符串 
     * @return int整型
     */
    public int editDistance (String str1, String str2) {
        // write code here
        //dp[i][j]表示从起点开始到str1[i]与str2[j]的最小操作次数
        int n1 = str1.length(), n2 = str2.length() ;
        int [][] dp = new int [n1+1][n2+1] ;
        for(int i=1; i<=n1; i++){
            dp[i][0] = dp[i-1][0] + 1 ;
        }
        for(int j=1; j<=n2; j++){
            dp[0][j] = dp[0][j-1] + 1 ;
        }
        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-1],Math.min(dp[i-1][j], dp[i][j-1])) + 1 ;
                }
            }
        }
        return dp[n1][n2] ;
    }
}

15、 最长的括号子串

题目链接:最长的括号子串_牛客题霸_牛客网

思路:借助栈实现,如果是左括号入栈,遇到右括号需要进行判断,若栈元素小于2,则直接先出栈,让当前元素下标入栈,反之直接出栈,并求出当前得最长括号字串。

Java版:

import java.util.*;


public class Solution {
    /**
     * 
     * @param s string字符串 
     * @return int整型
     */
    public int longestValidParentheses (String s) {
        // write code here
        Stack <Integer> stack = new Stack<>() ;
        stack.add(-1) ;
        int ans = 0 ;
        for(int i=0; i<s.length(); i++){
            if(s.charAt(i) == '('){
                stack.add(i) ;
            }else{
                if(stack.size() > 1){
                    stack.pop() ;
                    ans = Math.max(ans, i-stack.peek()) ;
                }else{
                    stack.pop() ;
                    stack.add(i) ;
                }
            }
        }
        return ans ;
    }
}

16、打家劫舍1

题目链接:打家劫舍(一)_牛客题霸_牛客网

思路:隔一家偷一家,这种情况,递推dp[i] = max(dp[i-1], dp[i-2]+nums[i]) ;

Java版:
 

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int rob (int[] nums) {
        // write code here
        int n = nums.length ;
        int [] dp = new int [n] ;
        dp[0] = nums[0] ;
        if(n>1){
            dp[1] = Math.max(nums[0], nums[1]) ;
        }
        for(int i=2; i<n; i++){
            dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i]) ;
        }
        return dp[n-1] ;
    }
}

17、打家劫舍2

题目链接:打家劫舍(二)_牛客题霸_牛客网

思路:环状的圈,需要判断第一个是否取,分两种可能讨论即可。

Java版:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int rob (int[] nums) {
        // write code here
        int n = nums.length ;
        int [] dp = new int [n] ;
        dp[0] = nums[0] ;
        dp[1] = nums[0] ;
        for(int i=2; i<n; i++){
            if(i==n-1){
                dp[i] = Math.max(dp[i-1], dp[i-2]) ;
            }else{
                dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i]) ;
            }
        }
        int ans = dp[n-1] ;
        Arrays.fill(dp, 0) ;
        dp[1] = nums[1] ;
        for(int i=2; i<n; i++){
            dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i]) ;
        }
        int max = (ans > dp[n-1]) ? ans : dp[n-1] ;
        return max ;
     }
}

18、买卖股票的最好时机(一)

题目链接:买卖股票的最好时机(一)_牛客题霸_牛客网

思路:用二维数组的持有和抛出思路更合理一点,比较通用。

Java版:

import java.util.*;


public class Solution {
    /**
     * 
     * @param prices int整型一维数组 
     * @return int整型
     */
    public int maxProfit (int[] prices) {
        // write code here
        int n = prices.length ;
        int [][] dp = new int [n][3] ;
        dp[0][0] = 0 ;
        dp[0][1] = -prices[0] ;
        dp[0][2] = 0 ;
        for(int i=1; i<n; i++){
            dp[i][0] = dp[i-1][0] ;
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]) ;
            dp[i][2] = Math.max(dp[i-1][2], dp[i-1][1] + prices[i]) ;
        }
        return dp[n-1][2] ;
    }
}

19、 买卖股票的最好时机(二)

题目链接:买卖股票的最好时机(二)_牛客题霸_牛客网

思路:还是老模板,只不过换成可以多次交易,递推表达式稍作修改,注:从1开始遍历

Java版:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 计算最大收益
     * @param prices int整型一维数组 股票每一天的价格
     * @return int整型
     */
    public int maxProfit (int[] prices) {
        // write code here
        int n = prices.length ;
        int [][] dp = new int [n][2] ;
        dp[0][0] = 0 ;
        dp[0][1] = -prices[0] ;

        for(int i=1; i<n; i++){
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]) ;
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]) ;
        }
        return dp[n-1][0] ;
    }
}

20、买卖股票的最好时机(三)

题目链接:买卖股票的最好时机(三)_牛客题霸_牛客网

思路:两次购票,dp[n][5]分别代表未持有、第一次持有与抛出、第二次持有与抛出。

Java版:

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 两次交易所能获得的最大收益
     * @param prices int整型一维数组 股票每一天的价格
     * @return int整型
     */
    public int maxProfit (int[] prices) {
        // write code here
        int n = prices.length ;
        int [][] dp = new int [n][5] ;
        dp[0][0] = 0 ;
        dp[0][1] = -prices[0] ;
        dp[0][2] = dp[0][3] = dp[0][4] = -100000 ;
        for(int i=1; i<n; i++){
            dp[i][0] = dp[i-1][0] ;
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]) ;
            dp[i][2] = Math.max(dp[i-1][2], dp[i-1][1] +  prices[i]) ;
            dp[i][3] = Math.max(dp[i-1][3], dp[i-1][2] - prices[i]) ;
            dp[i][4] = Math.max(dp[i-1][4], dp[i-1][3] + prices[i]) ;
        } 
        return dp[n-1][4] ;
    }
}

猜你喜欢

转载自blog.csdn.net/nuist_NJUPT/article/details/130877312