笔试训练,牛客.合唱团牛客.kannan与高音牛客.拜访(BFS)牛客.买卖股票的最好时机(四)

目录

牛客.合唱团

牛客.kannan与高音

牛客.拜访(BFS)

牛客.买卖股票的最好时机(四) 


牛客.合唱团

dp[i][j]:从1到i,中挑选最大乘积是多少,但是我们会发现状态转移方程推不出来,我们不知道如何推导的任意两个人,

从[1,i]中挑选,最大乘积是多少

dp[i][j]:从[1,i]中挑选,把j个人,最大乘积(arr[i]:必选,此时的一个最大乘积),因为我们知道获取这个状态值的时候,我们会知道,后面选当前位置的时候,前面那些人应该选择那哪些位置

f[i][j]:表示从[1,i]中挑选,挑选j个人,最后一个人必定选择,此时的最大乘积

g[i][j]:表示从[1,i]中挑选,最后一个人必选,此时的最小乘积。

返回值:

f[n][k],f[k][k]。

3.状态转移方程:

f[i][j]=Math.max(g[prev][j-1]*a[i],f[prev][j-1]*a[i]);

g[i][j]=Math.min(f[prev][j-1]*a[i],f[prev][j-1]*a[i]);

初始化

对角线以下,包括对角线

初始化:第一列会有可能越界,前i个里面选1个,且最后一个是必定选的,我们要记住,就好初始化了。

返回值

从f[k][k]-f[n][k]的max

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
            int n = in.nextInt();
            long[]arr=new long[55];
            for(int i=1;i<=n;i++){
             arr[i]=in.nextLong();
            }
            int k= in.nextInt();
            int d=in.nextInt();
            long[][]f=new long[55][15];
            long[][]g=new long[55][15];
          
            //填写每一行
            for(int i=1;i<=n;i++)
            {   f[i][1]=g[i][1]=arr[i];
                //假如i比较小的话,你从这么多k里面挑选不出来的是
                for(int j=2;j<=Math.min(k,i);j++){
                    //初始化,里面都初始化为无穷
                    f[i][j]=-0x3f3f3f3f3f3f3f3fL;
                    g[i][j]=0x3f3f3f3f3f3f3f3fL;
                    //两个中的最小值,他这里的比较,你要知道是比较什么
f[I][j],保存的是上一个位置的值,因为从i个人里面选j个,的前一个状态是prev里面选j-1个,f[i][j]:
最后的比较是因为prev也在不断的变化,我们需要从i-d到,j-1到i-1保存一个最大的。f[i][j]看图

                    for(int prev=Math.max(i-d,j-1);prev<=i-1;prev++){
                        f[i][j]=Math.max(Math.max(f[prev][j-1]*arr[i],g[prev][j-1]*arr[i]),f[i][j]);
                        g[i][j]=Math.min(Math.min(f[prev][j-1]*arr[i],g[prev][j-1]*arr[i]),g[i][j]);
                    }
                }  
            }
            long ret=-0x3f3f3f3f3f3f3f3fL;
            //f[k][k]-f[n][k]之间的最大值
            for(int i=k;i<=n;i++){
            ret=Math.max(ret,f[i][k]);
            }
            System.out.println(ret);
            
    }
}

牛客.kannan与高音

开始的时候,我以为这个和之前那个最长递增子序列是一种类型,另外还是最优解,我直接想的就是用动态规划,但是发现动态规划无法使用,因为他是连续的子数组,而不是子序列,他是截取一段连续的序列,所以不可以是用什么dp[i][j]减去xx啥的。

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n = in.nextInt();
        int[]a = new int[n + 1]; 
        long max=1;
        //dp[i][j]表示以j位置开启,i位置结束的最大长度
        for (int i = 1; i <= n; i++) {
            a[i] = in.nextInt();
        }

        for(int i=1;i<=n;){
        int left=i;
        int right=i+1;
        long count = 1;
         while(left<=n&&right<=n&&a[right]-a[left]<=8){
            count++;
            left++;
            right++;
         }
         i=right;
         max=Math.max(max,count);
        }

        System.out.print(max);
    }
}

牛客.拜访(BFS)

单元最短路问题。​​​​​​​

这是我做过比较难的bfs问题,需要存储的东西,如果你想不到这个表,那么就会比较麻烦了,所以我们需要这两张表,确实蛮复杂,比我想象的,但是摸索下来还是可以有一些思路的

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * @param CityMap int整型二维数组
     * @param n int整型
     * @param m int整型
     * @return int整型
     */
    static int[]dx = {0, 0, 1, -1};
    static int[]dy = {1, -1, 0, 0};
    public int countPath (int[][] CityMap, int n, int m) {
       //从起点位置到当前点的最短距离
        int[][]dist=new int[n][m];
        //从起点位置到当前位置最短距离的方案长度
        int[][]count=new int[n][m];
        Queue<int[]>q = new LinkedList<>();
        int ret=1;
        int[]d = new int[2];
        for (int i = 0; i < n; i++) {
            Arrays.fill(dist[i],-1);
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (CityMap[i][j] == 2) {
                    q.add(new int[] {i, j});
                    count[i][j]=1;
                    dist[i][j] = 0;
                } else if (CityMap[i][j] == 1) {
                    d[0] = i;
                    d[1] = j;
                }
            }
        }
        while (!q.isEmpty()) {
            int x=0;
            int y=0;
//sz代表每次进入q的组数,一次进两组的话,那么就这两组往上下左右遍历,遍历之后,最短的距离就+1
            int sz = q.size();
            while (sz != 0) {
                int[]t = q.poll();
                for (int i = 0; i < 4; i++) {
                    x = t[0] + dx[i];
                    y = t[1] + dy[i];
                    if (x >= 0 && x < n && y >= 0 && y < m && CityMap[x][y] != -1) {
//这里这个dist[x][y]假如是-1,那么说明第一次过来,我们需要把这个值,赋值成当前距离
                        if (dist[x][y] == -1) {
                            q.add(new int[]{x, y});
                            dist[x][y] = ret;
                            //第一次到达这个位置,需要等于他的上一个位置,因为是第一次到达,所以这个数字也是初始值1。
                            count[x][y] = count[t[0]][t[1]];
                        } else {
                            //观察是不是最短的距离。假如他是最短距离的话,那么他前面那个最短位置+1就会到目标位置,此时这个位置,就需要继承他的那个相当于父亲位置。
                            if (dist[t[0]][t[1]] + 1 == dist[x][y]) {
                                count[x][y] += count[t[0]][t[1]];
                            }
                        }
                    }
                }
                sz--;
            }
//ret这个值代表,从起点出发,到终点的最短距离,每次一组遍历,一个上下左右合记为一步,所以说,ret在最后++
            ret++;
        }
        return count[d[0]][d[1]];
    }
}

牛客.买卖股票的最好时机(四) 

​​​​​​​

 public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int n=in.nextInt();
        int k=in.nextInt();
        int[]prices=new int[n+1];
        for(int i=0;i<n;i++){
            prices[i]=in.nextInt();
        }
        //第i笔交易下第j天结束后最后一次状态是买入的最大收入
        int[][]f=new int[n][k+1];
        //第i笔交易下,第j天结束最后一次状态是卖出的最大收入
        int[][]g=new int[n][k+1];
        for(int i=0;i<=k;i++){
            f[0][i]=-0x3f3f3f3f;
            g[0][i]=-0x3f3f3f3f;
        }
        k=Math.min(k,n/2);
        f[0][1]=-prices[0];
        g[0][0]=0;

            for(int i=1;i<n;i++){
                for(int j=1;j<=k;j++){
                f[i][j]=Math.max(f[i-1][j],g[i-1][j-1]-prices[i]);
                g[i][j]=Math.max(g[i-1][j],f[i-1][j]+prices[i]);
            }
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狗哥不是甜妹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值