3.19美团笔试代码记录
当时只a了两道,太菜了。下来自己把题目全写了一遍,在此记录分享。
第一题
点外卖用折扣价还是用满减,直接模拟就行。唯一的坑是满减只能用最接近的券,比如商品总原价100,我有满100减10的券和满50-30的券,则只能用前者。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
long[] originPrice = new long[n];
long[] discountPrice = new long[n];
long sum = 0;
for(int i = 0; i < n; ++i) {
sum += in.nextInt();
originPrice[i] = sum;// 前i件商品原始价
}
sum = 0;
for(int i = 0; i < n; ++i) {
sum += in.nextInt();
discountPrice[i] = sum;
}
int m = in.nextInt();
int[] c = new int[m];
int[] d = new int[m];
for(int i = 0; i < m; ++i){
c[i] = in.nextInt();
}
for(int i = 0; i < m; ++i) {
d[i] = in.nextInt();
}
String res = "";
for(int i = 0; i < n; ++i) { // n件商品
long curManPrice = originPrice[i];
for(int j = 0; j < m; ++j) {
if(originPrice[i] >= c[j]) {
curManPrice = Math.min(curManPrice, originPrice[i] - d[j]);
}
else {
break;
}
}
if(curManPrice > discountPrice[i]) {
res += "Z";
}
else if(curManPrice < discountPrice[i]) {
res += "M";
}
else {
res += "B";
}
}
System.out.println(res);
}
}
第二题
加解密,直接模拟就行。这里可不自己用StringBuilder,因为字符串的加操作会自动优化为StringBuilder。
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int t = in.nextInt();
String str = in.next();
//System.out.println(str);
ArrayList<Character> list = new ArrayList<>();
for(char c : str.toCharArray()) {
list.add(c);
}
String res = "";
if(t == 2) { // 解密
while(list.size() > 0) {
char c = list.remove(list.size()-1);
int pos = res.length() / 2;
String s1 = res.substring(0,pos);
String s2 = res.substring(pos);
res = s1 + c + s2;
}
}
if(t == 1) { // 加密
while(list.size() > 0) {
int pos = list.size() % 2 == 0 ? list.size()/2-1 : (list.size()/2);
res += list.remove(pos);
}
}
System.out.println(res);
} 第三题
区间覆盖,双重循环,判断任意两个区间有无交集即可。注意,一台机器上本身的区间之间可能有重合,可以先进行区间合并,也可以直接用set记录。
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m1 = in.nextInt();
int m2 = in.nextInt();
int[][] intervals1 = new int[m1][2];
for(int i = 0; i < m1; ++i) {
intervals1[i][0] = in.nextInt();
}
for(int i = 0; i < m1; ++i) {
intervals1[i][1] = in.nextInt();
}
int[][] intervals2 = new int[m2][2];
for(int i = 0; i < m2; ++i) {
intervals2[i][0] = in.nextInt();
}
for(int i = 0; i < m2; ++i) {
intervals2[i][1] = in.nextInt();
}
Arrays.sort(intervals1, (v1, v2) -> (v1[0] - v2[0])); // 按区间左端点排序
Arrays.sort(intervals2, (v1, v2) -> (v1[0] - v2[0]));
Set<Integer> set = new HashSet<>(); // 去重
for(int i = 0; i < m1; ++i) {
for(int j = 0; j < m2; ++j) {
if(intervals1[i][0] > intervals2[j][1] || intervals1[i][1] < intervals2[j][0]) { // 没有交集
continue;
}
// 有交集:找交集的左右端点
int left = Math.max(intervals1[i][0], intervals2[j][0]);
int right = Math.min(intervals1[i][1], intervals2[j][1]);
for(int k = left; k <= right; ++k) {
set.add(k);
}
}
}
System.out.println(set.size());
}
} 第四题
给定n个元素的集合,从集合中选k个元素求和,使其和能被k1整除,不能被k2整除。(1 <= k <= n) 参考力扣78. 子集,直接回溯遍历所有可能的和,再依次判断。不能全a,但能快速拿一些分支的分。
import java.util.Scanner;
//5 3 4
//6 8 -2 -5 2
//输出:9 2 表示6、8、-5
public class Main {
private static int maxSum = 0;
private static int maxSumPlans = 0;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt(); // 5个数
int k1 = in.nextInt();
int k2 = in.nextInt();
int[] nums = new int[n];
for(int i = 0; i < n; ++i) {
nums[i] = in.nextInt();
}
// 输出总和与方案数
dfs(nums, 0, 0, k1, k2);
System.out.println(maxSum + " " + maxSumPlans);
}
private static void dfs(int[] nums, int curSum, int begin, int k1, int k2) {
for(int i = begin; i < nums.length; ++i) {
curSum += nums[i] % 998244353;
if(curSum % k1 == 0 && curSum % k2 != 0) { // 可被k1整除而不能被k2整除
if(curSum > maxSum) {
maxSum = curSum;
maxSumPlans = 1;
}
else if(curSum == maxSum) {
maxSumPlans++;
}
}
dfs(nums, curSum, i+1, k1, k2);
curSum -= nums[i];
}
}
} 第五题
当时没时间写了,把题目抄了下来,然后发现这道题甚至是5道里最简单的一题。。。直接模拟。不能全a,但能拿一大半分支的分。
对于一个序列A,我们定义序列(A+1)为将序列A里每个元素值都加1得到的序列。 例如:[3, 4, 2]+1=[4, 5, 3],[1, 2, 1]+1=[2, 3, 2]。 对于序列A和B,我们定义序列C=A*B表示序列C是由序列A和序列B拼接而成(序列A在前,序列B在后)。 例如:[2, 3, 1]*[1, 2, 1]=[2, 3, 1, 1, 2, 1]; [1, 2, 3]*[2, 3]*[5, 4]=[1, 2, 3, 2, 3]*[5, 4]=[1, 2, 3, 2, 3, 5, 4]。 小团得到了一个魔法盒子。 将序列A放入魔法盒子内,将会弹出序列(A+1)*A*(A+2)。 小团先将仅由一个数0构成的序列[0]放入魔法盒子,然后不断将魔法盒子弹出的序列再次放入。现在小团想问,他这样操作第n次时魔法盒子弹出序列中第k个位置的值是多少? 例如:一开始的序列为[0],第1次放入后弹出的结果是[1, 0, 2],第2次是[2, 1, 3, 1, 0, 2, 3, 2, 4],第3次是[3, 2, 4, 2, 1, 3, 4, 3, 5, 2, 1, 3, 1, 0, 2, 3, 2, 4, 4, 3, 5, 3, 2, 4, 5, 4, 6]。 一行两个空格隔开的整数n,k,表示初始序列为[0],小团想知道第n次弹出的序列的第k个数是多少。 输入:n k 数据保证 :1<=n<=35, 1<=k<=3^n 输出:一个整数,表示第n次弹出的序列的第k个数。
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
ArrayList<Integer> list = new ArrayList<>();
list.add(0);
while (n-- > 0) {
Box(list);
}
System.out.println(list.get(k - 1));
}
private static void Box(ArrayList<Integer> list) {
ArrayList<Integer> temp = new ArrayList<>(list);
ArrayList<Integer> temp1 = new ArrayList<>(list);
for(int i = 0; i < list.size(); ++i) {
list.set(i, temp.get(i)+1); // (A+1)
}
list.addAll(temp); // (A+1)*A
for(int i = 0; i < temp1.size(); ++i) {
temp1.set(i, temp1.get(i)+2);
}
list.addAll(temp1); // (A+1)*A*(A+2)
}
} 