美团0309春招实习笔试
个人参加的第一场笔试,之前虽然了解过相关的笔试题型(公众号)。自己参加,感叹还得多练啊~
0309.T1
1. 题目说明
MT 是美团的缩写,因此小美很喜欢这两个字母。
现在小美拿到了一个仅由大写字母组成字符串,她可以最多操作k次,每次可以修改任意一个字符。小美想知道,操作结束后最多共有多少个’M’和’T’字符?
输入描述
第一行输入两个正整数,代表字符串长度和操作次数。第二行输入一个长度为的、仅由大写字母组成的字符串。1<=k<=n<=10^5
输出描述
输出操作结束后最多共有多少个’M’和’T’字符。
示例 1
输入
5 2
MTUAN
输出
4
说明
修改第三个和第五个字符,形成的字符串为 MTTAM,这样共有 4 个’M’和’T’。
2. 解答分析
-
基础字符的处理,只用找出包含
M和T的数量,统计计算即可;
3. 具体代码
import java.util.Scanner;
public class test111 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a=in.nextInt();
int k=in.nextInt();
String s=in.next();
int count=0;
for(int i=0;i<a;i++){
if(s.charAt(i)=='M' || s.charAt(i)=='T'){
count++;
}else if((s.charAt(i)!='M' || s.charAt(i)!='T') && k>0){
count++;
k--;
}
}
System.out.println(count);
}
}
- 复杂度:
- 时间复杂度:
。指的是数组的长度n - 空间复杂度:
,并未用到其余结构
- 时间复杂度:
0309.T2
1. 题目说明
小美拿到了一个由正整数组成的数组,但其中有一些元素是未知的(用 0 来表示)。
现在小美想知道,如果那些未知的元素在区间[l,r]范围内随机取值的话,数组所有元素之和的最小值和最大值分别是多少?
共有q次询问。
输入描述
第一行输入两个正整数n,q,代表数组大小和询问次数。
第二行输入n个整数ai,其中如果输入ai的为 0,那么说明ai是未知的。
接下来的q行,每行输入两个正整数l,r,代表一次询问。
1<=n,q<=10^5
0<=ai<=10^9
1<=l<=r<=10^9
输出描述
输出q行,每行输出两个正整数,代表所有元素之和的最小值和最大值。
示例 1
输入
3 2
1 0 3
1 2
4 4
输出
5 6
8 8
说明
只有第二个元素是未知的。
第一次询问,数组最小的和是 1+1=3=5,最大的和是 1+2+3=6。
第二次询问,显然数组的元素和必然为 8。
2. 解答分析
-
这里最初的想法是统计
0出现的个数,但是这样写会导致时间复杂度的增加,从而超时。 -
回头想想,
0出现的次序貌似并不重要,我们最后只需要求最大值和最小值,所以只用统计0的个数即可,最后在sum上加减即可。 -
还要注意的是
long类型的问题,一般要看清楚输入的数值的取值大小
3. 具体代码
import java.util.Scanner;
public class test222 {
public static void main(String[] args) {
// Scanner in = new Scanner(System.in);
// int n=in.nextInt(); //数组大小
// int q=in.nextInt(); //访问次数
// long[]a =new long[n];
// int count=0; //统计a[i]为0的个数
// long res=0; //统计非0元素之和
//
// for(int i=0;i<n;i++){
// a[i]=in.nextLong();
// res+=a[i];
// if(a[i]==0){
// count++;
// }
// }
// for(int j=0;j<q;j++){
// long l=in.nextLong();
// long r=in.nextLong();
// long res1=res,res2=res;
// for(int i=0;i<count;i++){
// res1+=l;
// res2+=r;
// }
// System.out.println(res1+" "+res2);
// }
// 上述代码的通过率只有86%,存在超时的情况...
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int q = in.nextInt();
int[] a = new int[n];
int cnt = 0;
int sum = 0;
for (int i = 0; i < n; i++) {
a[i] = in.nextInt();
if (a[i] == 0) {
cnt++;
}
sum += a[i];
}
for (int j = 0; j < q; j++) {
int l = in.nextInt();
int r = in.nextInt();
System.out.println((sum + zeros * l) + " " + (sum + zeros * r));
}
}
}
-
复杂度:
-
时间复杂度:
O(n)
-
前两道题目都是常规的思路,基本上看完题目就可以写出来。但是需要注意超时的问题,下面的第三题开始就需要技巧了。
0309.T3
1. 题目说明
小美拿到了一个n*n 的矩阵,其中每个元素是 0 或者 1。
小美认为一个矩形区域是完美的,当且仅当该区域内 0 的数量恰好等于 1 的数量。
现在,小美希望你回答有多少个i*i的完美矩形区域。你需要回答1<=i<=n的所有答案。
输入描述
第一行输入一个正整数n,代表矩阵大小。
接下来的n行,每行输入一个长度为n的01 串,用来表示矩阵。(1<=n<=200)
输出描述
输出n行,第i行输出的I*I 完美矩形区域的数量。
示例 1
输入
4
1010
0101
1100
0011
输出
0
7
0
1
- 这里要注意输入字符的顺序吧,比如
1010,实际输入的顺序中含有空格:1 0 1 0;
2. 解答分析
-
这里真的不用遍历二维数组的每一个位置,而是统计数组中的元素之和。
-
直接枚举所有的边长i的正方形,判断正方形的和是否为
i*i/2即可,用到的方法是二维前缀和;
3. 具体代码
- 在列出常规的代码之前,先利用的是比较通俗的解法,或者说是直接看出来的解法:
import java.util.Arrays;
import java.util.Scanner;
public class test222_1 {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
int n = in.nextInt(); //行列的数值
int q = 0; // 下标
char[][] arr=new char[n][n];
in.nextLine(); // 读入字符串
while(q < n){
arr[q]=in.nextLine().toCharArray(); //将字符串优化成数组
q++;
}
//
int[][][] dp = new int[n + 1][n + 1][2];
int [] ans=new int[n ];
for(int i = 0; i < n; i++){ //按照行进行遍历
for(int j = 0; j < n; j++){ //按照列进行遍历
for(int k = 0; k<Math.min(n - i,n - j); k++){ //边长为k的子矩阵
int count = 0;
for(int l = i; l <= i + k; l++){ //子矩阵的行中含有1的个数
if(arr[l][j + k] == '1') count++;
}
for(int l = j; l< j + k; l++){ //子矩阵的列中含有1的个数(第一列和第一行存在重复的元素,所以这里就没有遍历不等
if(arr[i + k][l] == '1') count++;
}
dp[i][j][1]=dp[i][j][0] + count; //统计得到的1的元素的个数,原先的+新统计的
if(dp[i][j][1] *2==(k + 1)*(k + 1)) ans[k]++; //注意数组的下标,判断,并且直接在ans数组上累计
dp[i][j][0]=dp[i][j][1]; //更新统计
}
}
}
for(int temp : ans){
System.out.println(temp);
}
}
}
- 前缀和
import java.util.Scanner;
public class test222 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[][] dp = new int[n][n];
// 按照上述进行遍历元素也可,下面这个方法比较常规
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dp[i][j] = scanner.nextInt(); //遍历数组
}
}
// 前缀和数组
int[][] pre = new int[n + 1][n + 1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + dp[i - 1][j - 1]; //前缀和
}
}
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
if (i + k >= n || j + k >= n) break;
int subMatrix = getSubMatrix(pre, i, j, i + k, j + k);
if (subMatrix * 2 == Math.pow(k + 1, 2)) {
ans[k]++;
}
}
}
}
for (int a : ans) {
System.out.println(a);
}
}
private static int getSubMatrix(int[][] pre, int x1, int y1, int x2, int y2) {
return pre[x2 + 1][y2 + 1] - pre[x1][y2 + 1] - pre[x2 + 1][y1] + pre[x1][y1];
}
}
//