2024虾皮春季笔试真题

本文为原创内容,转载请注明出处并附带原文链接。感谢您的尊重与支持!

你必须非常努力,才能看起来毫不费劲。


1.有效的重复字符

题目描述

给定一个经过编码的字符串,按照特定规则返回它解码后的字符串。

编码规则为: k{string},表示大括号内部的 string 经过解码后重复 k 次,k 保证为正整数,string 经过解码后为由 a-z 之间的字符组成的字符串,即大括号可能会有嵌套的情况。你可以认为输入字符串总是有效的:输入字符串中没有额外的空格,且输入的括号总是符合格式要求的。

原始数据不包含数字,所有的数字只表示重复的次数 k,例如不会出现像 3a 或 2{4}的输入,但是会出现像a3{b4{c}de}的情况。

输入描述

输入一个经过编码的字符串。

输出描述

输出解码后的字符串。

输入示例

3{a2{c}}

输出示例

accaccacc

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.util.*;

public class Main{
public static void main(String[] args){
// 纯模拟,力扣原题:https://leetcode.cn/problems/decode-string/description
Scanner sc = new Scanner(System.in);
String x = sc.nextLine();
String curstring = "";
int num = 0;
Stack<String> strStack = new Stack<>();
Stack<Integer> numStack = new Stack<>();
for(int i = 0;i<x.length();i++){
char a = x.charAt(i);
if(a == '{'){
numStack.push(num);
strStack.push(curstring);
num = 0;
curstring = "";
}else if(a == '}'){
StringBuilder sb = new StringBuilder(strStack.pop());
int count = numStack.pop();
for(int j = 0;j<count;j++){
sb.append(curstring);
}
curstring = sb.toString();

}else if(Character.isDigit(a)){
num = num * 10 + a - '0';
}else {
curstring += a;
}
}
System.out.println(curstring);
}
}

2.字符-数字卡片拼电话号码

题目描述

幼儿园老师与小朋友做游戏,老师准备一个电话号码,幼儿从一叠识字卡片(每张卡片上有09, AZ, a~z中的一个字母)中抽出任意(大于零)张卡片,顺序展示,然后进行如下操作:

1、选择任意连续的若干张卡片,并将这些卡片按从小到大顺序排列

任意多次操作后,若所有卡片组成的字符串与老师展示的电话号码完全相同,则该幼儿游戏成功,输出1,否则失败,输出0,若有字母,输出-1

给出电话号码,及N个幼儿选择的卡片序列,预测此轮游戏的结果。

输入描述

输入包含两行。

第一行输入待拼成的号码number,以字符串表示。

第二行输入一个以字符串形式表示的数组cardListArray,表示每个小朋友们抽到的卡片组合,N表示小朋友的数量。

1 <= N <= 100;
3 <= number.length <= 11;
3 <= cardListArray[i].length <= 11。

输出描述

输出一个以字符串表示的数组,数组中仅有三种元素[0, 1, -1]。
含义见题目描述。
注意:输出的数组中,数字与数字之间没有空格,用逗号分隔。

输入示例

191
[119,911,19,129,1A9]

输出示例

[0,1,0,0,-1]

提示信息

对于第1个小朋友抽到的卡牌,没办法变成老师准备的号码,所以是0;
对于第2个小朋友抽到的卡牌,选择第一张和第二张卡牌进行排序可以得到19,与第三张卡牌可以凑成191,可以变成老师准备的号码,所以是1;
对于第3个小朋友抽到的卡牌,没办法变成老师准备的号码,所以是0;
对于第4个小朋友抽到的卡牌,没办法变成老师准备的号码,所以是0;
对于第5个小朋友抽到的卡牌,包含字母,所以是-1。
时间限制:c/c++/go:1s;其他语言:3s。

参考答案:

本题的核心思路是:

先用哈希表判断 card 是否与 num 由相同的数字组成(字符频率一致),然后通过贪心策略尝试将 card 通过最少的交换变为 num,如果能完成转换,则标记为 1,否则标记为 0,若 card 含有非数字字符则标记为 -1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import java.util.*;

public class Main {
public static void main(String[] args) {
// 哈希表计数 + 贪心交换模拟
Scanner sc = new Scanner(System.in);
String num = sc.nextLine();
String cardsStr = sc.nextLine().trim();
cardsStr = cardsStr.substring(1, cardsStr.length() - 1); // 去掉首尾的方括号
String[] cards = cardsStr.split(",");

int[] res = new int[cards.length];
Arrays.fill(res, -1);

Map<Character, Integer> map = new HashMap<>();
for (char c : num.toCharArray()) {
map.put(c, map.getOrDefault(c, 0) + 1);
}
for (int i = 0; i < cards.length; i++) {
String card = cards[i];
boolean hasLetter = false;
for (char a : card.toCharArray()) {
if (Character.isLetter(a)) {
hasLetter = true;
}
}
if (hasLetter) continue;
Map<Character, Integer> count = new HashMap<>();
for (char c : card.toCharArray()) {
count.put(c, count.getOrDefault(c, 0) + 1);
}
if (!count.equals(map)) {
res[i] = 0;
continue;
}

char[] s = card.toCharArray();
boolean isValid = true;
for (int j = s.length - 1; j >= 0; j--) {
char target = num.charAt(j);
if (target == s[j]) continue;

int index = -1;
int maxValue = s[j];
for (int k = j - 1; k >= 0; k--) {
if (s[k] > maxValue) {
maxValue = s[k];
}
if (target == s[k]) {
index = k;
break;
}
}

if (index == -1 || maxValue > target) {
isValid = false;
break;
}

for (int k = index; k < j; k++) {
s[k] = s[k + 1];
}
s[j] = target;
}

res[i] = isValid ? 1 : 0;
}

// 输出结果
StringBuilder result = new StringBuilder("[");
for (int i = 0; i < res.length; i++) {
if (i > 0) {
result.append(",");
}
result.append(res[i]);
}
result.append("]");
System.out.println(result.toString());
}
}

3.最接近的三数之和

题目描述

给定一个包括n个整数的数组nums和 一个目标值target。找出nums中的三个整数,使得它们的和与target最接近。输出这三个数的和。假定每组输入只存在唯一答案。

输入描述

输入包含两行。

第一行是n个空格隔开的整数,表示数组nums;

第二行是一个整数target。

3 <= n <= 1000
-1000 <= nums[i] <= 1000
-10000 <= target <= 10000

输出描述

输出一个整数,表示最近接的三数之和。

输入示例

-1 2 1 -4
1

输出示例

2

提示信息

与 target 最接近的和是2(-1 + 2 + 1 = 2) 。

时间限制:c/c++/go:0.5s;其他语言:2s。

参考答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.util.*;

public class Main {
public static void main(String[] args) {
// 三指针就完了
Scanner sc = new Scanner(System.in);
String[] numStrs = sc.nextLine().split(" ");
int[] arr = new int[numStrs.length];

for (int i = 0; i < numStrs.length; i++) {
arr[i] = Integer.parseInt(numStrs[i]);
}
int target = sc.nextInt();
Arrays.sort(arr);

// 力扣原题:https://leetcode.cn/problems/3sum-closest/description
int n = arr.length;
int res = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
// 剪枝
if (i > 0 && arr[i] == arr[i - 1]) {
continue;
}

int left = i + 1;
int right = n - 1;
while (left < right) {
int sum = arr[i] + arr[left] + arr[right];

if (Math.abs(target - sum) < Math.abs(target - res)) {
res = sum;
}
if (sum > target) right--;
else if (sum < target) left++;
else {
System.out.println(sum);
return;
}
}
}
System.out.println(res);
}
}