恭喜发现宝藏!微信搜索公众号【TechGuide】关注更多新鲜好文和互联网大厂的笔经面经。
作者@TechGuide【全网同名】
点赞再看,养成习惯,您动动手指对原创作者意义非凡🤝
文章目录
第一道: 找数(100%)
小美和小团在玩游戏。小美将会给出 n 个大小在 1 到 n 之间(包括 1 和 n)的整数,然后小美会再告诉小团一个整数 k,小团需要找到一个最小的整数 x 满足以下条件:
整数x的大小在 1 到 n 之间(包括1和n)
在小美给出的 n 个整数中,恰好有 k 个数严格比 x 小
输入描述
第一行是一个数 T,表示有 T 组数据。
对于每组数据:
第一行有两个整数 n 和 k,分别表示小美将会给出 n 个数以及她给出的整数k。
接下来一行有 n 个用空格隔开的正整数,表示小美给出的 n 个正整数。
输出描述
对于每组数据:
如果存在满足要求的数 x,第一行先输出 “YES”(不含引号),第二行输出数 x 的值。
如果不存在满足要求的数 x,输出 “NO”(不含引号)。
样例输入
1
2
3
4
5
2
6 6
1 6 6 2 1 3
6 3
1 6 5 2 2 5
样例输出
1
2
3
NO
YES
3
提示
数据范围和说明
30%的数据保证 n<=10, 0<=k<=n, T<=10
60%的数据保证 n<=1000, 0<=k<=n, T<=10
100%的数据保证 n<=100000, 0<=k<=n, T<=10
java版
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for(;t > 0; t--){
int n = sc.nextInt();
int k = sc.nextInt();
int[] nums = new int[n];
for (int i = 0; i < nums.length; i++) {
nums[i] = sc.nextInt();
}
int ans = fun(nums, n, k);
if(ans == -1) System.out.println("NO");
else{
System.out.println("YES");
System.out.println(ans);
}
}
}
private static int fun (int[] nums, int n, int k) {
Arrays.sort(nums);
for (int x = 1; x <= n; x++) { // 穷举 x
int xiao = 0;
int da = 0;
for (int j = 0; j < nums.length; j++) {
if(nums[j] > x) da++;
if(nums[j] < x) xiao++;
}
if(xiao == k) return x;
}
return -1;
}
}
CPP版
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N, K;
int main(){
int T ;
cin>>T;
while(T--){
cin>>N >> K;
vector<int> data(N);
for(int i=0;i<N;i++)
cin >> data[i];
sort(data.begin(), data.end());
int ans;
if(K>N){
cout<< "NO" <<endl;
continue;
}
if(K==0)
ans = 1;
else
ans = data[K-1] + 1;
if(ans < 1 || ans > N){
cout<<"NO"<<endl;
continue;
}
if(K<N && data[K-1]==data[K]){
cout<< "NO" <<endl;
continue;
}
cout<<"YES"<<endl;
cout<<ans<<endl;
}
}
Python版
T = int(input())
for _ in range(T):
n, k = map(int, input().split())
num = list(map(int,input().split()))
num.sort()
if n==k:
if num[n-1]+1 <= n:
print(num[n-1]+1)
else:
print('NO')
else:
# 主要报错部分
if num[k-1]+1 >= 1 and num[k-1]+1 <= n and num[k-1]+1 <= num[k]:
print('YES')
print(num[k-1]+1)
else:
print('NO')
第二道:奇怪键盘(100%)
小美得到了一个奇怪的键盘,上面一共有 53 个按键,包括 26 个小写字母、26 个大写字母和空格。这个键盘的奇怪之处如下:
当小美按下一个按键时,该按键可能会被多次触发,即输出一连串按下按键所对应的字符。
键盘会时不时地自动按下空格键。
在使用这个键盘来进行输入时,小美保证了相邻两次按下的按键一定不同以及不主动按下空格键,现在给你小美使用这个键盘输入一个字符串后得到的结果,请你还原小美原本想要输入的这个字符串。
输入描述
一行,一个包含小写字母、大写字母和空格的字符串,表示小美输入后得到的结果。
输出描述
输出一行,表示小美原本想要输入的字符串。
样例输入
1
a iC C C GmyyyySp p
样例输出
1
aiCGmySp
提示
数据范围和说明
30%的数据保证 输入的字符串长度<=20
60%的数据保证 输入的字符串长度<=1000
100%的数据保证 输入的字符串长度<=100000
java版本
import java.util.Scanner;
public class Main {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
String b = s.trim();
StringBuilder sb = new StringBuilder(b);
for(int i = 1; i < sb.length(); i++){
if(sb.charAt(i) == ' '){
sb.deleteCharAt(i);
i--;
}
}
for (int i = 1; i < sb.length(); i++) {
if(sb.charAt(i) == sb.charAt(i-1)){
sb.replace(i-1, i, " ");
}
}
for(int i = 1; i < sb.length(); i++){
if(sb.charAt(i) == ' '){
sb.deleteCharAt(i);
i--;
}
}
System.out.println(sb);
}
}
CPP版
#include<iostream>
#include<vector>
using namespace std;
int main(){
string str;
getline(cin,str);
string ret;
for(int i=0 ; i<str.size() ;i++){
if(str[i] == ' ')
continue;
else{
ret+=str[i];
int tmp = i+1;
while( tmp <str.size() && (str[tmp] == str[i] || str[tmp] == ' ') )
tmp++;
i = tmp-1;
}
}
cout<<ret<<endl;
return 0;
}
Python版
a = str(input())
ans1 = []
ans = []
# 删除空格
for i in range(len(a)):
if a[i] != ' ':
ans1.append(a[i])
# 删除重复元素
for j in range(len(ans1)):
if j==0:
ans.append(ans1[0])
elif ans1[j] != ans1[j-1]:
ans.append(ans1[j])
# 列表转化为字符串
out = ''.join(b for b in ans)
print(out)
第三道 序列问题(100%)
小美有一个长度为 n 的序列 A,A[i] 表示序列中第 i 个数(1<=i<=n)。她定义序列中第 i 个数的 prev[i] 值 为前 i-1 个数中比 A[i] 小的最大的值,即满足 1<=j<i 且 A[j]<A[i] 中最大的 A[j],若不存在这样的数,则 prev[i] 的值为 0。现在她想要你帮忙计算对于所有的 i,prev[i]*i 之和是多少。
输入描述
第一行是一个整数 n 表示序列的长度。
接下来一行 n 个数用空格隔开,第 i 个数表示 A[i] 的大小。
输出描述
一行一个整数,表示答案。
样例输入
1
2
5
1 6 3 3 8
样例输出
1
39
提示
数据范围和说明
30%的数据保证 n<=20,1<=A[i]<=100。
60%的数据保证 n<=1000,1<=A[i]<=1000。
100%的数据保证 n<=100000,1<=A[i]<=100000。
建图,答案是节点数-连通块数。对于a[i],找到之前小于它的最大的数,可以维护一个set,每次处理完当前a[i],就插入到set中。对于处理,可以直接利用set的lower_bound(val),然后根据迭代器减1判断情况。
CPP版
#define ll long long;
using namespace std;
int main() {
int n;
scanf("%d",&n);
set<int> st;
long long ans = 0;
for (int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if (st.size()){
auto it= lower_bound(st.begin(),st.end(),x);
it--;
if (it!=st.end()){
ans+=i*(*it);
}
}
st.insert(x);
}
cout<<ans<<endl;
return 0;
}
java版
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long sum = 0;
int[] nums = new int[n];
for(int i = 0; i < n; i++){
nums[i] = sc.nextInt();
}
int[] prev = new int[n];
TreeSet<Integer> set = new TreeSet<>();
for(int i = 0; i < n; i++){
int temp = nums[i];
Integer top = set.floor(temp);
if(top == null){
prev[i] = 0;
}else{
if(temp == top){
set.remove(temp);
Integer nextTmp = set.floor(temp);
prev[i] = nextTmp == null ? 0 : nextTmp;
set.add(temp);
}else{
prev[i] = top;
}
}
set.add(temp);
}
for(int i = 1; i < n; i++){
sum += (i + 1) * prev[i];
}
System.out.println(sum);
}
第四道 最少操作次数(100%)
小美给了小团一个长度为 n(n为偶数)的序列 A,序列中的数都是介于 [1,100000] 的整数。小团想把这个序列变得漂亮后再送回给小美。小美觉得一个序列是漂亮的当且仅当这个序列的前一半和后一半是一样的,即对于 1<=i<=n/2 都满足 A[i]==A[i+n/2]。
小团可以按进行以下操作任意次:
选择两个介于 [1, 100000] 之间的数 x 和 y,然后将序列 A 中所有值为 x 的数替换为 y。
注意,每次操作都会在上一次操作后得到的序列上进行。小团想知道他最少需要操作多少次可以把序列变成漂亮的。
输入描述
第一行是一个整数 n,表示序列的长度。数据保证 n 为偶数。
第二行有 n 个用空格隔开的整数,第 i 个数表示 A[i] 的值。数据保证 1<=A[i]<=100000。
输出描述
输出小团需要的最少操作次数。
样例输入
1
2
10
4 2 1 5 2 10 2 1 5 8
样例输出
1
2
提示
数据范围和说明
30%的数据保证 n<=10,1<=A[i]<=10000。
70%的数据保证 n<=1000,1<=A[i]<=10000。
100%的数据保证 n<=100000,1<=A[i]<=10000。
任选x修改为y,使得序列前一半与后一半相同,可以处理出不同的 pair{ a[i] , a[i+n/2] },然后默认first为较小值,去一下重 ( 相同的对计算一次贡献 ),然后建立无向图。优先从入度小的点出发DFS,每走一步就是一个花费,图遍历完就得答案。
并查集
Java版
public class Main {
private static int x = 10001;
private static int[] next = new int[x], count = new int[x];
public static void main(String[] args) {
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
Scanner s = new Scanner(System.in);
int n = s.nextInt();
int[][] tmp = new int[n/2][2];
for (int i = 0; i < n / 2; i++) tmp[i][0] = s.nextInt();
for (int i = 0; i < n / 2; i++) tmp[i][1] = s.nextInt();
for (int i = 0; i < next.length; i++) {
next[i] = i;
count[i] = 1;
}
for (int i = 0; i < n / 2; i++) {
if (tmp[i][0]!=tmp[i][1]){
union(tmp[i][0],tmp[i][1]);
}
}
int res = 0;
for (int i = 0; i < x; i++) {
if (i==find(i)) res += (count[i]-1);
}
System.out.println(res);
}
private static void union(int i, int j){
int ii = find(i);
int jj = find(j);
if (ii==jj) return;
if (count[ii]>count[jj]){
next[jj] = ii;
count[ii] += count[jj];
}else{
next[ii] = jj;
count[jj] += count[ii];
}
}
private static int find(int i){
while(next[i]!=i) i = next[i];
return i;
}
}
CPP版
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int getIndex(vector<int>& tree , int num){
int l = 0 , r = tree.size() -1;
while(l<r){
int mid = (l+r)>>1;
if(tree[mid] == num)
return mid;
if(tree[mid] > num)
r = mid;
else
l = mid + 1;
}
return l;
}
int findroot(vector<int> & tree , int x){
if(tree[x] != -1){
tree[x] = findroot(tree,tree[x]);
return tree[x];
}else
return x;
}
int main(){
int N;
cin>>N;
vector<int> data(N);
for(int i=0;i<N;i++)
cin>>data[i];
vector<int> tmp(data);
sort(tmp.begin(),tmp.end());
tmp.erase( unique(tmp.begin(),tmp.end()) , tmp.end());
vector<int> tree(tmp.size(),-1);
int ans = 0;
for(int i=0;i<N/2 ;i++){
if(data[i] != data[i+N/2]){
int x = getIndex(tmp,data[i]) , y = getIndex(tmp,data[i+N/2]);
int xroot = findroot(tree,x) , yroot = findroot(tree,y);
if(xroot!=yroot){
tree[xroot] = yroot;
ans++;
}
}
}
cout<< ans <<endl;
return 0;
}
第五道:对换左右子树(100%)
交换二叉树的左右孩子节点然后输出中序遍历结果。可以直接用数组表示存二叉树,点值对应题目要求的点序号,下标0开始,初始时左右儿子分别为2x+1,2x+2,然后根据修改,分别修改Lchild和Rchild的指向。第五题代码还没删掉,如下。
#include<bits/stdc++.h>
using namespace std;
int a[100020];
typedef pair<int,int> pii;
int n,m,k;
int loc[100020];
struct node{
int val;
int L,R;
}p[10000];
struct pre{
int L,R;
}has[10000];
void solve(int x) {
if(x>=n) return;
loc[p[x].val]=x;
p[x].L=p[x].R=0;
int cur=p[x].val;
int Lval=has[cur].L;
int Rval=has[cur].R;
if(Lval) {
p[x].L=2*x+1;
p[2*x+1].val=Lval;
solve(2*x+1);
}
if(Rval) {
p[x].R=2*x+2;
p[2*x+2].val=Rval;
solve(2*x+2);
}
}
void print(int x) {
if(p[x].L) print(p[x].L);
cout<<p[x].val<<" ";
if(p[x].R) print(p[x].R);
}
int main()
{
cin>>n>>m>>k;
p[0].val=k;
for(int i=1;i<=n;i++) {
cin>>has[i].L>>has[i].R;
}
solve(0);
for(int i=1;i<=m;i++) {
int x;
cin>>x;
int id=loc[x];
swap(p[id].L,p[id].R);
}
print(0);
}