动态规划算法

1、最长公共序列

dp[i][j]:表示字符串1与字符串2在索引为i与j时,最长的公共序列。
初始化:无
循环:双层循环一层字符串1的长度,一层字符串2的长度;
转移:
-若两个索引恰好相同:dp[i][j] = dp[i - 1][j - 1]
-若两个索引不相同:dp[i][j] = Math.max(dp[i][j - 1],dp[i - 1][j])

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        
        int len1 = scanner.nextInt();
        int len2 = scanner.nextInt();
        String str1 = scanner.next();
        String str2 = scanner.next();
        
        int[][] dp = new int[len1 + 1][len2 + 1];
        
        for(int i = 1; i <= len1; i++){
            char c1 = str1.charAt(i - 1);
            for(int j = 1; j <= len2; j++){
                char c2 = str2.charAt(j - 1);
                if(c1 == c2){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }else{
                    dp[i][j] = Math.max(dp[i - 1][j],dp[i][j - 1]);
                }        
            }
        }
        System.out.println(dp[len1][len2]);
    }
}
2、乘积为正的最长连续子数组

dp[i][0]:表示前i个数为正数的最长长度
dp[i][1]:表示前i个数为负数的最长长度
初始化:因为dp第零个数为正或是负长度都为0
循环:双层循环一层字符串1的长度,一层字符串2的长度;
转移:
-若当前元素为正:

  • dp[i][0]的转移:前i - 1个数为正的最大长度加一 dp[i][0] = dp[i - 1][0] + 1;
  • dp[i][1]的转移:前i - 1个数为负的数量如果不为0,说明前面有负数,此时这个数为正数,那么相乘后,负数的长度有加1,所以要先if判断dp[i - 1][1] ? 0,不为0就对dp[i][1] = dp[i - 1][1] + 1

-若当前元素为负数:

  • dp[i][1]的转移:前i - 1个数为正的最大长度加一 dp[i][1] = dp[i - 1][0] + 1;道理相同,成绩得为负
  • dp[i][0]的转移:前i - 1个数为负的数量不为0,说明前面有负数,此时这个数为负数,那么相乘后,正数长度加1,dp[i][0] = dp[i - 1][1] + 1;

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int size = scanner.nextInt();
        int[] nums = new int[size];
        
        for(int i = 0; i < size; i++){
            nums[i] = scanner.nextInt();
        }
        
        int[][] dp = new int[size + 1][2];
        int res = 0;
        for(int i = 1; i <= size; i++){
            int val = nums[i - 1];
            if(val > 0){
                dp[i][0] = dp[i - 1][0] + 1;
                if(dp[i - 1][1] != 0){
                    dp[i][1] = dp[i - 1][1] + 1;
                }
            }else if(val < 0){
                dp[i][1] = dp[i - 1][0] + 1;
                if(dp[i - 1][1] != 0){
                    dp[i][0] = dp[i - 1][1] + 1;
                }
            }
            res = Math.max(res,dp[i][0]);
        }
        System.out.println(res);
    }
}

3、环形数组的连续子数组最大和

题目:

描述
给定一个长度为 nn 的环形整数数组,请你求出该数组的 非空 连续子数组 的最大可能和 。
环形数组 意味着数组的末端将会与开头相连呈环状。例如,对于数组 [1,3,-5,2,-4][1,3,−5,2,−4]而言,第一个数 11的前一个数是最后一个数 -4−4。
输入:
3
5 -3 5
输出:
10
说明:从子数组 [5,5] 得到最大和 5 + 5 = 10

分析

结果分为两种情况:
1、最大的和在中间,没有两端分开
2、最大的和在左右两端,中间是最小值(二者相加等于数组总和)
表示:
premax:表示上一项的最大和值;max:表示最大的和值
premin:表示上一项的最小和值;min:表示最小和值
若最后的max>0,则可能存在两端最大的情况使用Math.max(sum-min,max)作比较;
若最后的max<0,则表示大家都是负的,直接用max就行

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int size = sc.nextInt();
        int[] nums = new int[size];
        for(int i = 0; i < size; i++){
            nums[i] = sc.nextInt();
        }
        
        int sum = nums[0]; int premax = nums[0]; int max = nums[0];
        int premin = nums[0]; int min = nums[0];
        for(int i = 1; i < size; i++){
            sum += nums[i];
            premax = Math.max(premax,0) + nums[i];
            max = Math.max(max,premax);
            premin = Math.min(premin,0) + nums[i];
            min = Math.min(min,premin);
        }
        int res = max > 0 ? Math.max(max,sum - min) : max;
        System.out.println(res);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值