【春招笔试】杂题选讲

开始春招寻找实习的过程中,遇到了很多场笔试。以赛代练,总结在笔试中经常出现的题目。

招行Fintech笔试 4.29

训练营分组 (dp思路+二分加速)

dp是类似于打家劫舍的思路,维护了区间的最值,转移方程是考虑是否选取当前点。
在这里插入图片描述

其实感觉笔试题目在看到解析的时候并不太难,但是很多时候思路被卡死的比较多。这个题目当时考虑了贪心的思路,每次都贪心的选取出来最大的一组,然后把这个过程重复两次。但是似乎还是存在错误。其实采用一个额外的dp数组维护就可以。dp[i]维护了区间nums[i, n-1]这个区间上,可以参与的最大人数。而对于转移方程的定义,分别考虑 i 这个位置是否参与选择,类似于打家劫舍的思路。使用二分法找到,选取这个 i 这个点以后右侧的最大点,然后计算长度,并且和不考虑这个点,也就是dp[i+1]比对,得到最大的dp[i]。

而我们要求选择两个区间,因此就是假设选择当前的数字和右端点的dp的最大值。

输入:
5 2
20
3
16
9
5
输出:
3

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        int[] a = new int[n];
        for(int i = 0;i<n;i++){
            a[i] = sc.nextInt();
        }
        int ans = 0;
        Arrays.sort(a);
        
        int[] dp = new int[n+1];
        for(int i = n-1;i>=0;i--){
        	// 这个index是无法满足条件的最小值。
            int index = bin(a, a[i]+k);
            // 分别是不选取当前点dp[i+1]和选取当前点index-i
            dp[i] = Math.max(dp[i+1], index-i);
            // 选取当前的,加上dp[index]表示以index为起点的最大值
            ans = Math.max(ans, index-i+dp[index]);
        }
        System.out.println(ans);

    }
    
    private static int bin(int[] a, int x){
        int n = a.length;
        int l = 0;
        int r = n-1;
        while(l<=r){
            int mid = (l+r)/2;
            if (a[mid]<x){
                l = mid+1;
            }else if (a[mid] == x){
                l = mid+1;
            }else{
                r = mid-1;
            }
        }
        return l;
    }

}

欢送回家 (dp,枚举最后一个选择的切分位置)

在这里插入图片描述

数据量不是很大,因此我们想到的方法dp可以支持到3次的循环。首先很显然我们在设计dp的时候就需要考虑到两维的属性,包括了用户和车辆数。这题目的破题点在于,枚举最后一个车辆的承载用户数量,我们很容易发现,计算一辆车在一个区间内的浪费的空间是非常容易的。因此我们枚举最后一辆车的浪费空间即可。

dp[i][j]表示考虑到第 i 个用户的时候,已经使用了 j 辆车的情况下,最小的浪费。转移方程dp[i][j] = Math.min(dp[i][j], dp[k][j-1]+xmax[k+1][i]*(i-k)-presum[i+1]+presum[k+1]); 也就是前k用户使用了j-1辆车,后面的[k+1, i]的用户使用一辆车。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int g = sc.nextInt();
        int[] a = new int[n];
        int max = 0;
        int[][] dp = new int[n][g+1];
        int sum = 0;
        int[] presum = new int[n+1];
        // 得到一辆大巴车的浪费情况,baseline
        for(int i = 0;i<n;i++){
            a[i] = sc.nextInt();
            sum += a[i];
            presum[i+1] = presum[i]+a[i];
            max = Math.max(max, a[i]);
            dp[i][1] = max*(i+1)-sum;
        }
        // xmax表示从i开始到j结束的最大值
        int[][] xmax = new int[n][n];
        for (int i = 0;i<n;i++){
            xmax[i][i] = a[i];
            for (int j = i+1;j<n;j++){
                xmax[i][j] = Math.max(a[j], xmax[i][j-1]);
            }
        }
    
        // 转移方程需要考虑到,最后一次分割
        for(int i = 0;i<n;i++){
            for (int j = 2;j<=Math.min(g,i+1);j++){
                dp[i][j] = dp[i][j-1];
                // 最后一辆车负责接送从k+1开始的学生
                for(int k = 0;k<i;k++){
                    //dp[i][j] = Math.min(dp[i][j], dp[k][j-1]+help(a, k+1, i+1));
                    // xmax[k+1][i]这个区间最大值乘以数量 - 实际的 = 浪费的
                    dp[i][j] = Math.min(dp[i][j], dp[k][j-1]+xmax[k+1][i]*(i-k)-presum[i+1]+presum[k+1]);
                }
            }
        }
        System.out.println(dp[n-1][g]);
        
    }  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值