251011 去哪儿AI面的笔试
侥幸做出来,分享一下
第一题
求nums中被三整除且不含三的数字个数
其中,可以对区间[l, r]进行一次操作,都+1或-1,也可以不操作。
求可能的个数的最大值和最小值
思路:分别计算+1和-1的差值数组后,计算它们最大连续子数组之和,得到最大值和最小值
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int n = in.nextInt();
int nums[] = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = in.nextInt();
}
// valid[0]表示原来nums数组的对应数字是否成立
// valid[1]和valid[2]表示nums对应数字+1和-1后是否还成立
int cnt = 0, valid[][] = new int[3][n];
for (int i = 0; i < n; i++) {
int x = nums[i], sum = 0;
if (check(nums[i])) {
valid[0][i] = 1;
cnt++;
}
if (check(nums[i]+1)) {
valid[1][i] = 1;
}
if (check(nums[i]-1)) {
valid[2][i] = 1;
}
}
int max = cnt, min = cnt;
for (int i = 0; i < n; i++) { // 分别计算+1和-1后的差值
valid[1][i] -= valid[0][i];
valid[2][i] -= valid[0][i];
}
int add1 = getBigest(valid[1]), add2 = getBigest(valid[2]); // 计算差值的最大值
for (int i = 0; i < n; i++) {
valid[1][i] = -valid[1][i];
valid[2][i] = -valid[2][i];
}
int del1 = -getBigest(valid[1]), del2 = -getBigest(valid[2]); // 计算差值的最小值(即计算负数的最大值的相反数)
int res[] = new int[2];
res[0] = cnt + Math.max(add1, add2);
res[1] = cnt + Math.min(del1, del2);
System.out.println(res[0] + " " + res[1]);
}
}
private static int getBigest(int nums[]) { // 获得nums的最大连续子数组之和
int n = nums.length;
int cur = 0, res = -(int)1e9;
for (int i = 0; i < n; i++) {
cur += nums[i];
res = Math.max(res, cur);
if (cur < 0) cur = 0;
}
return res;
}
private static boolean check(int x) { // x这个数字是否成立
int sum = 0;
while (x > 0) {
int cur = x % 10;
if (cur == 3) break;
sum += cur;
x /= 10;
}
return x == 0 && sum % 3 == 0;
}
}
第二题
对于一个区间[l,r],g(b)表示这个区间的中位数,min(l,r)表示区间的最小值
计算所有区间的g(b) - min(l,r)的最大值
思路:遍历每一个可能的中位数,贪心可以想到,这个中位数所在的区间越大越好,直到边界,可以拿到最小的min(l,r)。用两个方向的前缀最小值避免重复计算
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int T = in.nextInt();
for (int t = 0; t < T; t++) {
int n = in.nextInt(), nums[] = new int[n];
for (int i = 0; i < n; i++) nums[i] = in.nextInt();
// 两个方向的前缀最小值
int leftMin[] = new int[n], rightMin[] = new int[n];
leftMin[0] = nums[0]; rightMin[n-1] = nums[n-1];
for (int i = 1; i < n; i++) {
leftMin[i] = Math.min(leftMin[i-1], nums[i]);
}
for (int i = n-2; i >= 0; i--) {
rightMin[i] = Math.min(rightMin[i+1], nums[i]);
}
// 0 1 2 ->
// 0 1 2 3 4->
int res = 0;
for (int i = 0; i < n; i++) {
if (i <= n/2) { // 中位数在左边,找到区间的右边界
int r = Math.min(n-1, i*2);
res = Math.max(res, nums[i] - leftMin[r]);
} else { // 中位数在右边,找到区间的左边界
int l = i - (n-i);
res = Math.max(res, nums[i] - rightMin[l]);
}
}
System.out.println(res);
}
}
}
}
查看19道真题和解析