算法简单笔记4

5月31号,明天决赛,今天脑子也是一滩浆糊,踏马的一道题也做不出来,超级难受,只好简单复盘一下两道之前的题目,看完就差不多了,再学也没啥用了,写完这两题题解我就回去打把steam绝地求生,听天由命等死吧

复盘之前基础题:

一、经典动态规划:最长递增子序列

很基础的动态规划题,思路如下:

我们遍历整个数组,每遍历到第 i 位,我们就把【从第0位 ~ 第i位作为一个新数组,来计算以这个第 i 位为结尾的数组里,可以第 i 位组成最长递增子序列的长度是多少

我们用一个dp[ ]数组记录下每一个第 i 位结尾的最长递增子序列的长度是多长

那么我们知道,假如 j < i,如果 “第 j 位的数 < 第 i 位的数” ,那么第 i 位的数就可以跟【第 j 位为结尾的最长递增子序列】组成一个新的最长子序列

那这个【第 i 位为结尾的最长递增子序列的长度就等于 ——>【第 j 位为结尾的最长递增子序列的长度+1

完整代码:

import java.util.Arrays;
import java.util.Scanner;

public class 最长递增子序列 {
    public static void main(String[] args){
        //我这里懒得按照题目要求输入了,直接输入原数组序列,知道逻辑就行
        Scanner in = new Scanner(System.in);
        System.out.print("请输入这个数组有几个成员:");
        int n = in.nextInt();
        System.out.print("请输入这"+n+"个数字:");
        long []a = new long[n];
        for (int i = 0; i < n; i++) {
            a[i] = in.nextLong();
        }

        long[] dp = new long[n];
        Arrays.fill(dp,1);//全部初始化为1,也就是每个第i位数字自己就是一个数组的时候的长度就是1

        long maxLength = 1;//记录最大递增子序列的
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if(a[j] < a[i]){
                    dp[i] = Math.max(dp[i] , dp[j]+1);
                }
            }
            maxLength = Math.max(maxLength , dp[i]);
        }

        System.out.println(maxLength);
    }
}

二、经典动态规划:最长递增子序列的个数

在上一题的基础要统计个数,看似烧脑麻烦,但其实多写几组样例还是能看出简单的规律的

思路:

1、我们除了用dp[ ]数组记录每一个的最长子序列的长度以外,再设一个count[ ]数组,记录每一个【第 i 位为结尾的数组】有几个最长递增子序列

2、如果dp[ j ] + 1 > dp[ i ],那么就说明【第 j 位为结尾的最长递增子序列】可以跟【第 i 位】组成新的最长子序列,那么第 j 位有几个最长递增子序列,第 i 位也就跟他一样有几个

即:count[i] = count[j]

趣味理解:j 有N个最长递增子序列,那我 i 是他爹,我更应该也有N个)

3、如果dp[ j ] + 1 == dp[ i ],那么就说明找到了相同长度的递增子序列,那么就应该在count[ i ]原来最多有N条的最长子序列的基础上,再加上count[ j ]拥有的最多的递增子序列

即:count[i] += count[j]

趣味理解:j 跟 j+1 都有10万块,那我CEO在本来就有15万的基础上,也要再加10万块)

4、不过还是要建立在a[ j ] < a[ i ]的情况,你都不比他大就说明你们凑不成一个递增子序列

5、但是因为我们根据dp[ j ] + 1 > dp[ i ] 和 dp[ j ] + 1 == dp[ i ]来更新最多的递增子序列的个数,那么我们只能获取到“【以i为结尾的】、【最后长度最长】”的递增子序列的个数,但是要知道最后结尾的数也可能不止一个

按照这个例子,那么我们实际想要的是【以7为结尾的最长子序列】2个 + 【以6为结尾的最长子序列】2个 = 4个!!

那么就还得用一个【maxLength】记录下最长子序列的长度

然后遍历dp[ ]数组,找到最后长度是最长子序列长度的位置if (dp[ i ] == maxLength)

然后把这些位置为结尾的拥有的最长子序列的个数累加resulet += count[ i ]

最后这个result才是整个原数组拥有的最长递增子序列的个数

趣味理解:最后两个同级别的CEO大佬,都掌握2亿资产,那么它两加起来的4亿才是这个公司最屌工资的总数)

完整代码:

import java.util.*;
public class 最长递增子序列的个数 {
    public static void main(String[] args){
        //我这里懒得按照题目要求输入了,直接输入原数组序列,知道逻辑就行
        Scanner in = new Scanner(System.in);
        System.out.print("请输入这个数组有几个成员:");
        int n = in.nextInt();
        System.out.print("请输入这"+n+"个数字:");
        long []a = new long[n];
        for (int i = 0; i < n; i++) {
            a[i] = in.nextLong();
        }

        long[] dp = new long[n];
        long[] count = new long[n];

        Arrays.fill(dp,1);
        Arrays.fill(count,1);

        long maxLength = 0;//记录最大递增子序列的

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if(a[j] < a[i]){
                    if(dp[j]+1 > dp[i]){
                        dp[i] = dp[j]+1;
                        count[i] = count[j];
                    } else if (dp[j]+1 == dp[i]) {
                        count[i] += count[j];
                    }
                }
            }
            maxLength = Math.max(maxLength , dp[i]);
        }

        long result = 0;
        for (int i = 0; i < n; i++) {
            if(dp[i] == maxLength){
                result += count[i];
            }
        }
        System.out.println(result);
    }
}

不写了玛德,心烦了,只想吃个鸭腿跟热卤,回去打两把游戏睡觉

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值