阿里智能 阿里智能笔试 0411
笔试时间:2025年04月11日
历史笔试传送门:
第一题
题目
对于给定的长为 n、由大小写字母混合构成的字符串 8,将其全部小写字母选出,得到新的字符串 t (可能为空),记下标从 1 开始,对 t 进行排序,使得:
t 中奇数位置的字母均不小于其相邻的字母
t 中偶数位置的字母均不大于其相邻的字母
因为这样的字符串具有波浪形,故称其为波浪字符串。这里的大小即为字母表中的顺序,'a' 最小,'z' 最大。你只需要直接输出排序后的字符串 t 即可.
输入描述
第一行输入一个整数n(1 ≤ n ≤ 10^5),表示字符串s 的长度。
第二行输入一个长度为 n、由大小写字母混合构成的字符串 s
输出描述
输出一个仅由小写字母构成的字符串,表示最终得到的t如果存在多个解决方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
样例输入
6
ciallo
样例输出
liocla
参考题解
从控制台读取一个整数表示字符串长度,再读取一个由大小写字母混合构成的字符串。然后从该字符串中提取出所有小写字母,将这些小写字母进行排序,最后按照特定规则(奇数位置字母不小于相邻字母,偶数位置字母不大于相邻字母 )重新排列这些小写字母并输出。
C++:[此代码未进行大量数据的测试,仅供参考]
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void reverse(vector<char>& arr) {
int i = 0, j = arr.size() - 1;
while (i < j) {
swap(arr[i], arr[j]);
i++;
j--;
}
}
int main() {
int n;
cin >> n;
cin.ignore(); // consume newline
string s;
getline(cin, s);
vector<char> t;
for (char c : s) {
if (islower(c)) {
t.push_back(c);
}
}
sort(t.begin(), t.end());
int m = t.size();
if (m == 0) {
cout << endl;
return 0;
}
int mid = (m + 1) / 2;
vector<char> larger(t.end() - mid, t.end());
vector<char> smaller(t.begin(), t.end() - mid);
reverse(smaller);
vector<char> result(m);
int l = 0, sIdx = 0;
for (int i = 0; i < m; i++) {
if (i % 2 == 0)
result[i] = larger[l++];
else
result[i] = smaller[sIdx++];
}
for (char c : result)
cout << c;
cout << endl;
return 0;
}
Java:[此代码未进行大量数据的测试,仅供参考]
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public staticvoid main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.nextLine();
String s = sc.nextLine();
StringBuilder tBuilder = new StringBuilder();
for (char c : s.toCharArray()) {
if (Character.isLowerCase(c)) {
tBuilder.append(c);
}
}
char[] t = tBuilder.toString().toCharArray();
Arrays.sort(t);
int m = t.length;
if (m == 0) {
System.out.println();
return;
}
int mid = (m + 1) / 2;
char[] larger = Arrays.copyOfRange(t, m - mid, m);
char[] smaller = Arrays.copyOfRange(t, 0, m - mid);
reverse(smaller);
char[] result = new char[m];
int l = 0, sIdx = 0;
for (int i = 0; i < m; i++) {
if (i % 2 == 0) {
result[i] = larger[l++];
} else {
result[i] = smaller[sIdx++];
}
}
System.out.println(newString(result));
}
private staticvoid reverse(char[] arr) {
int i = 0, j = arr.length - 1;
while (i < j) {
char tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
}
Python:[此代码未进行大量数据的测试,仅供参考]
n = int(input())
s = input()
t = [c for c in s if c.islower()]
t.sort()
m = len(t)
if m == 0:
print()
else:
mid = (m + 1) // 2
larger = t[-mid:]
smaller = t[:m - mid][::-1] # reversed
result = []
l = sIdx = 0
for i in range(m):
if i % 2 == 0:
result.append(larger[l])
l += 1
else:
result.append(smaller[sIdx])
sIdx += 1
print("".join(result))
第二题
题目
Tk 有一个长度为 n 的排列,但是正如他总是遗忘自己各种账号的密码一样,他记不起来这个排列的具体构造。好在他现在还记得这个排列的最长上升子序列是一个长度为 m 的子序列。现已知该最长上升子序列为 (a1, a2, ..., am) ,请你利用这些数据还原原排列。请注意:最长上升子序列可能不唯一。
【排列】排列为由 (1 ~ n) 这 n 个整数按任意顺序组成的数组,其中每个整数恰好出现一次。例如,({2, 3, 1, 5, 4}) 是一个长度为 5 的排列;而 ({1, 2, 2}) 和 ({1, 3, 4}) 均不是排列,因为前者存在重复元素,后者包含了超出范围的数。
输入描述
第一行输入两个整数 (n, m) ((1<= m <= n <= 2 * 10^5),分别表示原排列的长度以及该排列的最长上升子序列的长度。
第二行输入 m 个正整数 (a1, a2, ..., am) ((1<= ai <= n)) 表示最长上升子序列。
这里的子序列为从原排列中删除若干(可以为零、可以全部)元素得到的新序列,且不要求连续。
输出描述
输出一行 n 个整数,表示构造出的原排列,可以证明这样的排列一定存在。
如果存在多个解决方案,您可以输出任意一个。
系统会自动判定您的答案是否正确。
请注意:自测运行功能可能返回错误结果,请您自行仔细检查答案是否正确。
样例输入
4 2
2 3
样例输出
4 2 3 1
参考题解
根据给定的排列长度 n 和该排列的最长上升子序列(LIS)长度 m 以及具体的最长上升子序列元素,构造出一个满足条件的原排列。其核心思路是先找出不在最长上升子序列中的元素,将这些元素根据大小分为比最长上升子序列最后一个元素大的和小的两部分,然后
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
