🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员
✨ 本系列打算持续跟新灵犀互娱 近期的春秋招笔试题汇总~
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
文章目录
-
- [01.Z 字形编码](#01.Z 字形编码)
- 02.单词翻转
- 03.符文匹配
- 04.魔法学徒的算术考试
- 写在最后
- [📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取~](#📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取~)
01.Z 字形编码
问题描述
LYA 正在研究一种新的编码方式,称为 Z 字形编码。给定两个无符号 4 4 4 字节长度的整数 x x x 和 y y y,Z 字形编码的计算规则如下:
- 将 x x x 和 y y y 转换为二进制形式。
- 从 x x x 和 y y y 的二进制形式中交替取位,每次取 1 1 1 位,先从 x x x 的高位开始取,然后从 y y y 的高位开始取,依次类推,直到取完 x x x 和 y y y 的所有二进制位。
- 将取出的二进制位按顺序拼接,得到一个新的二进制数 z z z。
- 将 z z z 转换为无符号 8 8 8 字节长度的整数作为编码结果。
现在,LYA 有一些整数对需要进行 Z 字形编码,她想请你帮忙计算编码结果。
输入格式
第一行包含一个正整数 n n n,表示需要编码的整数对数量。
接下来 n n n 行,每行包含两个无符号 4 4 4 字节长度的整数 x x x 和 y y y,表示一个需要编码的整数对。
输出格式
输出共 n n n 行,每行一个无符号 8 8 8 字节长度的整数,表示对应整数对的 Z 字形编码结果。
样例输入
3
18 52
178 532
321 943
样例输出
1816
297752
484439
数据范围
- 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1≤n≤105
- 0 ≤ x , y < 2 32 0 \le x, y < 2^{32} 0≤x,y<232
题解
这道题考查的是位运算和二进制操作。我们可以分别从 x x x 和 y y y 的高位开始,依次取出一个二进制位,然后将其拼接到结果 z z z 的二进制形式中。重复这个过程,直到取完 x x x 和 y y y 的所有二进制位。
具体实现时,我们可以用移位操作和位与操作来取出 x x x 和 y y y 的二进制位。每次取出一位后,将 x x x 和 y y y 右移 1 1 1 位,直到 x x x 和 y y y 都变为 0 0 0。同时,我们用一个变量 z z z 来存储编码结果,每取出一位,就将其拼接到 z z z 的末尾,并将 z z z 左移 1 1 1 位。
时间复杂度为 O ( n ) O(n) O(n),其中 n n n 为整数对的数量。单次编码的时间复杂度为 O ( 1 ) O(1) O(1),因为整数的二进制位数是固定的。空间复杂度为 O ( 1 ) O(1) O(1)。
参考代码
- Python
python
def zorder(x, y):
z = 0
for i in range(32):
z = (z << 1) | ((x >> (31 - i)) & 1)
z = (z << 1) | ((y >> (31 - i)) & 1)
return z
n = int(input())
for _ in range(n):
x, y = map(int, input().split())
print(zorder(x, y))
- Java
java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
while (n-- > 0) {
String[] xy = br.readLine().split(" ");
int x = Integer.parseInt(xy[0]);
int y = Integer.parseInt(xy[1]);
System.out.println(zorder(x, y));
}
}
private static long zorder(int x, int y) {
long z = 0;
for (int i = 31; i >= 0; i--) {
z = (z << 1) | ((x >> i) & 1);
z = (z << 1) | ((y >> i) & 1);
}
return z;
}
}
- Cpp
cpp
#include <iostream>
using namespace std;
typedef unsigned int uint;
typedef unsigned long long ull;
ull zorder(uint x, uint y) {
ull z = 0;
for (int i = 31; i >= 0; i--) {
z = (z << 1) | ((x >> i) & 1);
z = (z << 1) | ((y >> i) & 1);
}
return z;
}
int main() {
int n;
cin >> n;
while (n--) {
uint x, y;
cin >> x >> y;
cout << zorder(x, y) << endl;
}
return 0;
}
02.单词翻转
题目描述
K小姐正在学习英语,一次考试中遇到一道单词翻转的题目。给定一个由多个单词构成的英文句子,要求将句子中的每个单词都翻转后输出,同时保持单词在句子中的相对位置不变。
输入格式
第一行包含一个正整数 T T T,表示总共有 T T T 组测试数据。
接下来 T T T 行,每行一个字符串,表示一个由多个单词构成的英文句子。每个句子的长度不超过 1023 1023 1023 个字符。
输出格式
对于每组测试数据,输出一行,每行包含翻转后的句子,单词之间用一个空格隔开。
样例输入
3
game
hello world
welcome to lingxi
样例输出
emag
olleh dlrow
emoclew ot ixgnil
数据范围
- 1 ≤ T ≤ 100 1 \leq T \leq 100 1≤T≤100
- 句子中单词数不超过 100 100 100 个
- 单词由小写英文字母构成
- 相邻单词之间用一个空格隔开,句首和句尾没有多余空格
题解
本题考查字符串的处理能力。我们可以按照如下步骤解决该问题:
- 读入一行字符串,表示一个句子。
- 将句子按照空格分割成若干个单词。
- 对每个单词进行翻转操作。
- 将翻转后的单词按照原有顺序拼接成新的句子并输出。
具体而言,我们可以使用字符串流(stringstream)来方便地实现单词的分割。将原句子作为字符串流的输入,然后通过 ">>" 运算符依次读取单词并存储到字符串 s 中。对于每个读入的单词,先进行翻转,再将翻转后的单词存储到结果数组中。
最后,遍历结果数组,将单词按顺序输出,相邻单词之间用空格隔开即可。
本题的时间复杂度为 O ( n ) O(n) O(n),其中 n n n 为句子的总字符数。空间复杂度也为 O ( n ) O(n) O(n)。
参考代码
- Python
python
t = int(input())
for _ in range(t):
line = input().split()
res = [word[::-1] for word in line]
print(' '.join(res))
- Java
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
sc.nextLine();
while (t-- > 0) {
String line = sc.nextLine();
String[] words = line.split("\\s+");
List<String> res = new ArrayList<>();
for (String word : words) {
res.add(new StringBuilder(word).reverse().toString());
}
System.out.println(String.join(" ", res));
}
}
}
- Cpp
cpp
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
void solve() {
string line;
getline(cin, line);
stringstream ss(line);
vector<string> res;
string word;
while (ss >> word) {
reverse(word.begin(), word.end());
res.push_back(word);
}
for (int i = 0; i < res.size(); i++) {
cout << res[i];
if (i < res.size() - 1) {
cout << " ";
}
}
cout << endl;
}
int main() {
int t;
cin >> t;
cin.ignore();
while (t--) {
solve();
}
return 0;
}
03.符文匹配
问题描述
K小姐踏上了一场充满神秘的符文之旅。她手中拥有记录着一串神秘符文 s 1 s_1 s1。经过漫长的探险,K小姐找到了另外一串更长的神秘符文序列 s 2 s_2 s2。现在,她需要判断 s 2 s_2 s2 中是否存在一个子串,使得该子串恰好由 s 1 s_1 s1 的所有字符按某种顺序组成,且每个字符只使用一次。
换言之,K小姐需要判断 s 1 s_1 s1 的任意一个排列是否为 s 2 s_2 s2 的子串。
输入格式
第一行包含一个正整数 T T T,表示测试数据的组数。
每组数据包含两行:
第一行为字符串 s 1 s_1 s1。
第二行为字符串 s 2 s_2 s2。
输出格式
对于每组测试数据,如果 s 2 s_2 s2 中存在 s 1 s_1 s1 的排列作为子串,则输出 true
,否则输出 false
。
样例输入
2
lingxi
aerlxngli
lingxi
aerlxngixi
样例输出
true
false
数据范围
- 1 ≤ T ≤ 100 1 \le T \le 100 1≤T≤100
- 1 ≤ ∣ s 1 ∣ ≤ ∣ s 2 ∣ ≤ 1 0 5 1 \le |s_1| \le |s_2| \le 10^5 1≤∣s1∣≤∣s2∣≤105
- 字符串 s 1 s_1 s1 和 s 2 s_2 s2 仅包含小写英文字母
题解
这道题可以用滑动窗口 + 哈希表的思路来解决。
首先,我们统计字符串 s 1 s_1 s1 中每个字符出现的次数,用哈希表 l l l 存储。
然后,我们在字符串 s 2 s_2 s2 上维护一个长度为 ∣ s 1 ∣ |s_1| ∣s1∣ 的滑动窗口,用另一个哈希表 r r r 统计窗口内每个字符出现的次数。
初始时,滑动窗口位于字符串 s 2 s_2 s2 的最左端。我们先统计窗口内字符出现的次数,如果此时两个哈希表相同,说明找到了一个合法的排列,可以直接返回 true
。
否则,我们不断右移滑动窗口,每次移动时:
- 去掉窗口最左端的字符,同时将哈希表 r r r 中对应的计数减 1 1 1,如果减到 0 0 0 则直接从哈希表中删除这个字符;
- 将窗口最右端新加入的字符加到哈希表 r r r 中,计数加 1 1 1。
然后比较两个哈希表是否相同,如果相同则说明找到了一个合法排列,返回 true
。
如果滑动窗口移动到最右端还没有找到合法排列,则返回 false
。
算法的时间复杂度为 O ( ∣ s 2 ∣ ) O(|s_2|) O(∣s2∣),空间复杂度为 O ( ∣ s 1 ∣ ) O(|s_1|) O(∣s1∣)。
参考代码
- Python
python
T = int(input())
for _ in range(T):
s1 = input().strip()
s2 = input().strip()
n, m = len(s1), len(s2)
if m < n:
print("false")
continue
l, r = {}, {}
for c in s1:
l[c] = l.get(c, 0) + 1
for c in s2[:n]:
r[c] = r.get(c, 0) + 1
if l == r:
print("true")
continue
for i in range(n, m):
r[s2[i-n]] -= 1
if r[s2[i-n]] == 0:
del r[s2[i-n]]
r[s2[i]] = r.get(s2[i], 0) + 1
if l == r:
print("true")
break
else:
print("false")
- Java
java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
while (T-- > 0) {
String s1 = br.readLine();
String s2 = br.readLine();
int n = s1.length(), m = s2.length();
if (m < n) {
System.out.println("false");
continue;
}
Map<Character, Integer> l = new HashMap<>(), r = new HashMap<>();
for (char c : s1.toCharArray()) {
l.put(c, l.getOrDefault(c, 0) + 1);
}
for (int i = 0; i < n; i++) {
char c = s2.charAt(i);
r.put(c, r.getOrDefault(c, 0) + 1);
}
if (check(l, r)) {
System.out.println("true");
continue;
}
for (int i = n; i < m; i++) {
char prev = s2.charAt(i - n), curr = s2.charAt(i);
r.put(prev, r.get(prev) - 1);
if (r.get(prev) == 0) {
r.remove(prev);
}
r.put(curr, r.getOrDefault(curr, 0) + 1);
if (check(l, r)) {
System.out.println("true");
break;
}
}
if (!check(l, r)) {
System.out.println("false");
}
}
}
private static boolean check(Map<Character, Integer> l, Map<Character, Integer> r) {
if (l.size() != r.size()) {
return false;
}
for (char c : l.keySet()) {
if (!r.containsKey(c) || !l.get(c).equals(r.get(c))) {
return false;
}
}
return true;
}
}
- Cpp
cpp
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
bool check(unordered_map<char, int>& l, unordered_map<char, int>& r) {
if (l.size() != r.size()) {
return false;
}
for (auto& [c, cnt] : l) {
if (!r.count(c) || r[c] != cnt) {
return false;
}
}
return true;
}
int main() {
int T;
cin >> T;
while (T--) {
string s1, s2;
cin >> s1 >> s2;
int n = s1.size(), m = s2.size();
if (m < n) {
cout << "false" << endl;
continue;
}
unordered_map<char, int> l, r;
for (char c : s1) {
l[c]++;
}
for (int i = 0; i < n; i++) {
r[s2[i]]++;
}
if (check(l, r)) {
cout << "true" << endl;
continue;
}
for (int i = n; i < m; i++) {
r[s2[i-n]]--;
if (r[s2[i-n]] == 0) {
r.erase(s2[i-n]);
}
r[s2[i]]++;
if (check(l, r)) {
cout << "true" << endl;
break;
}
}
if (!check(l, r)) {
cout << "false" << endl;
}
}
return 0;
}
04.魔法学徒的算术考试
题目描述
在魔法学校中,学徒们正在进行一场特殊的算术考试。这场考试的题目由数字和运算符组成,运算符包括加法 + + +、减法 − - −、乘法 ∗ * ∗ 和除法 / / /,其中加法和减法的优先级高于乘法和除法。学徒们需要按照题目给出的算术表达式计算出最终的结果。
输入格式
输入一行,包含一个由数字、运算符 + + +、 − - −、 ∗ * ∗、 / / /,以及空格组成的算术表达式。
输出格式
输出一个整数,表示算术表达式的计算结果。
样例输入
1 + 2 * 3 - 4 / 2
样例输出
5
数据范围
- 表达式中的所有数字均为正整数,且不超过 1 0 9 10^9 109。
- 表达式的长度不超过 100 100 100。
- 保证表达式合法,且计算过程中和最终结果均不超过 2 31 − 1 2^{31}-1 231−1。
题解
本题需要根据题目描述的运算符优先级,对算术表达式进行求值。我们可以使用两个栈 num_stack
和 op_stack
分别存储数字和运算符,具体步骤如下:
-
将字符串中的空格去掉,方便后续处理。
-
从左到右遍历字符串:
- 如果当前字符为数字,则连续读取数字并将其转化为整数,然后压入
num_stack
。 - 如果当前字符为左括号
(
,则直接压入op_stack
。 - 如果当前字符为右括号
)
,则不断弹出op_stack
的运算符并进行计算,直到遇到左括号为止。计算结果压入num_stack
。 - 如果当前字符为运算符,则:
- 如果
op_stack
为空,或者栈顶运算符为左括号,或者当前运算符优先级大于栈顶运算符,则直接压入op_stack
。 - 否则,不断弹出
op_stack
的运算符并进行计算,直到当前运算符优先级大于栈顶运算符。然后将当前运算符压入op_stack
。
- 如果
- 如果当前字符为数字,则连续读取数字并将其转化为整数,然后压入
-
遍历完字符串后,将
op_stack
中剩余的运算符依次弹出并进行计算。 -
最后
num_stack
中剩下的唯一一个数字即为表达式的结果。
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)。其中 n n n 为算术表达式的长度。
参考代码
- Python
python
mp = {'+': 3, '-': 3, '*': 2, '/': 2}
def calc(a, b, op):
if op == '+':
return a + b
elif op == '-':
return a - b
elif op == '*':
return a * b
else:
return a // b
s = input().replace(' ', '')
num_stack = []
op_stack = []
i = 0
while i < len(s):
if s[i].isdigit():
x = 0
while i < len(s) and s[i].isdigit():
x = x * 10 + int(s[i])
i += 1
num_stack.append(x)
elif s[i] == '(':
op_stack.append(s[i])
i += 1
elif s[i] == ')':
while op_stack and op_stack[-1] != '(':
num_b = num_stack.pop()
num_a = num_stack.pop()
op = op_stack.pop()
num_stack.append(calc(num_a, num_b, op))
op_stack.pop()
i += 1
else:
while op_stack and mp[op_stack[-1]] >= mp[s[i]]:
num_b = num_stack.pop()
num_a = num_stack.pop()
op = op_stack.pop()
num_stack.append(calc(num_a, num_b, op))
op_stack.append(s[i])
i += 1
while op_stack:
num_b = num_stack.pop()
num_a = num_stack.pop()
op = op_stack.pop()
num_stack.append(calc(num_a, num_b, op))
print(num_stack[0])
- Java
java
import java.io.*;
import java.util.*;
public class Main {
static Map<Character, Integer> mp = new HashMap<>();
static {
mp.put('+', 3);
mp.put('-', 3);
mp.put('*', 2);
mp.put('/', 2);
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine().replaceAll("\\s+", "");
Deque<Integer> numStack = new ArrayDeque<>();
Deque<Character> opStack = new ArrayDeque<>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (Character.isDigit(c)) {
int x = 0, j = i;
while (j < str.length() && Character.isDigit(str.charAt(j))) {
x = x * 10 + (str.charAt(j) - '0');
j++;
}
numStack.push(x);
i = j - 1;
} else if (c == '(') {
opStack.push(c);
} else if (c == ')') {
while (!opStack.isEmpty() && opStack.peek() != '(') {
calc(numStack, opStack);
}
opStack.pop();
} else {
while (!opStack.isEmpty() && opStack.peek() != '(' && mp.get(opStack.peek()) >= mp.get(c)) {
calc(numStack, opStack);
}
opStack.push(c);
}
}
while (!opStack.isEmpty()) {
calc(numStack, opStack);
}
System.out.println(numStack.pop());
}
private static void calc(Deque<Integer> numStack, Deque<Character> opStack) {
int b = numStack.pop(), a = numStack.pop();
char op = opStack.pop();
int c = 0;
if (op == '+') c = a + b;
else if (op == '-') c = a - b;
else if (op == '*') c = a * b;
else c = a / b;
numStack.push(c);
}
}
- Cpp
cpp
#include <iostream>
#include <string>
#include <stack>
#include <unordered_map>
using namespace std;
unordered_map<char, int> mp{{'+', 3}, {'-', 3}, {'*', 2}, {'/', 2}};
void calc(stack<int>& num_stack, stack<char>& op_stack) {
int b = num_stack.top(); num_stack.pop();
int a = num_stack.top(); num_stack.pop();
char op = op_stack.top(); op_stack.pop();
int c = 0;
if (op == '+') c = a + b;
else if (op == '-') c = a - b;
else if (op == '*') c = a * b;
else c = a / b;
num_stack.push(c);
}
int main() {
string str;
getline(cin, str);
string s;
for (char c : str) {
if (c != ' ') {
s += c;
}
}
stack<int> num_stack;
stack<char> op_stack;
for (int i = 0; i < s.size(); i++) {
if (isdigit(s[i])) {
int x = 0, j = i;
while (j < s.size() && isdigit(s[j])) {
x = x * 10 + (s[j] - '0');
j++;
}
num_stack.push(x);
i = j - 1;
} else if (s[i] == '(') {
op_stack.push(s[i]);
} else if (s[i] == ')') {
while (op_stack.size() && op_stack.top() != '(') {
calc(num_stack, op_stack);
}
op_stack.pop();
} else {
while (op_stack.size() && op_stack.top() != '(' && mp[op_stack.top()] >= mp[s[i]]) {
calc(num_stack, op_stack);
}
op_stack.push(s[i]);
}
}
while (op_stack.size()) {
calc(num_stack, op_stack);
}
cout << num_stack.top() << endl;
return 0;
}
写在最后
📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取~