今日头条2017后端工程师实习生笔试题

本文详细解析了今日头条后端工程师的笔试题目,包括最大映射、木棒拼图、魔法权值和或与加四个问题。通过分析思路,探讨了如何找到字符串映射的最大和、判断木棒能否构成简单多边形、解决特定权值字符串的数量以及求解满足特定条件的正整数y。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最大映射

有 n 个字符串,每个字符串都是由 A-J 的大写字符构成。现在你将每个字符映射为一个 0-9 的数字,不同字符映射为不同的数字。这样每个字符串就可以看做一个整数,唯一的要求是这些整数必须是正整数且它们的字符串不能有前导零。现在问你怎样映射字符才能使得这些字符串表示的整数之和最大?
输入描述:每组测试用例仅包含一组数据,每组数据第一行为一个正整数 n , 接下来有 n 行,每行一个长度不超过 12 且仅包含大写字母 A-J 的字符串。 n 不大于 50,且至少存在一个字符不是任何字符串的首字母。
输出描述:输出一个数,表示最大和是多少。
输入例子:
2
ABC
BCA
输出例子:
1875

思路

以题目的输入例子分析计算过程

ABC=100×A+10×B+C
BCA=100×B+10×C+A
则ABC+BCA=110×B+101×A+11×C(根据权值从大到小排序)。

要使和最大,则权值越大的映射的数字应越大,即B=9,A=8,C=7,故最大和为1875.
可以将n个字符串相加,根据以上方法求出每个字符的权值,并根据权值大小对字符从大到小进行排序。权值越大映射数字越大。注意,题目中要求了字符串不能有前导零,我们可以用一个标识符记录每个字符是否可为0。若权值最低的字符不能为0,则向前寻找可以为0且权重最小的字符,用该字符与权值最低的字符交换,同时权重向前移。。。例如

字符 权重 是否可为0(0表示可以)
A 100 1
J 11 1
C 10 0
D 9 0
E 8 1
B 7 0
G 6 0
H 5 1
I 4 1
F 3 1
权重最低的字符为F,它的标识符为0,则该字符可以为0,故寻找权重最小且可以为0的字符,在这个问题中,该字符为G。交换并向前移。即

字符 权重 是否可为0(1表示可以)
A 100 1
J 11 1
C 10 0
D 9 0
E 8 1
B 7 0
H 5 1
I 4 1
F 3 1
G 6 0

import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

public class Main{
    public static void main(String []args){
        Scanner cin=new Scanner(System.in);
        int n;
        while(cin.hasNext()){
            n=cin.nextInt();
            String[]str=new String[n];
            Element[]e=new Element[10];
            for(int i=0;i<10;i++)e[i]=new Element();
            for(int i=0;i<n;i++){
                str[i]=cin.next();
                int l=str[i].length();
                long base=1;
                for(int j=l-1;j>=0;j--,base*=10){
                    int idx=str[i].charAt(j)-'A';
                    // 标记该字符不能为0
                    if(j==0)e[idx].flag=1;
                    e[idx].w+=base;
                }
            }
            Arrays.sort(e, new Comparator<Element>(){

                @Override
                public int compare(Element o1, Element o2) {
                    //if(o1.flag!=o2.flag)return o1.flag-o2.flag;
                    return o1.w>o2.w?1:(o1.w==o2.w?0:-1);
                }

            });
            long s=0;
            // 权值最低且不能为0的情况
            if(e[0].flag==1){
                int k=0;
                for(;k<10;k++)if(e[k].flag==0)break;
                Element tmp=e[k];
                for(;k>0;k--)e[k]=e[k-1];
                e[0]=tmp;
            }
            // 权值越大映射的值越大
            for(int i=9;i>=0;i--){
                s+=e[i].w*i;
                //System.out.println(e[i].flag+" "+e[i].w);
            }

            System.out.println(s);

        }
    }
}
// 记录字符的权重和标识符,flag=0,表示该字符可以为0,反之,说明该字符不能为0.
class Element{
    long w;
    int flag;
}

木棒拼图

有一个由很多木棒构成的集合,每个木棒有对应的长度,请问能否用集合中的这些木棒以某个顺序首尾相连构成一个面积大于 0 的简单多边形且所有木棒都要用上,简单多边形即不会自交的多边形。
初始集合是空的,有两种操作,要么给集合添加一个长度为 L 的木棒,要么删去集合中已经有的某个木棒。每次操作结束后你都需要告知是否能用集合中的这些木棒构成一个简单多边形。
输入描述:
每组测试用例仅包含一组数据,每组数据第一行为一个正整数 n 表示操作的数量(1 ≤ n ≤ 50000) , 接下来有n行,每行第一个整数为操作类型 i (i ∈ {1,2}),第二个整数为一个长度 L(1 ≤ L ≤ 1,000,000,000)。如果 i=1 代表在集合内插入一个长度为 L 的木棒,如果 i=2 代表删去在集合内的一根长度为 L 的木棒。输入数据保证删除时集合中必定存在长度为 L 的木棒,且任意操作后集合都是非空的。
输出描述:
对于每一次操作结束有一次输出,如果集合内的木棒可以构成简单多边形,输出 “Yes” ,否则输出 “No”。
输入例子:
5
1 1
1 1
1 1
2 1
1 2
输出例子:
No
No
Yes
No
No

思路

这道题的主要问题是判断集合内的木棒是否可以构成简单多边形。由三角形的性质:“两边之和大于第三边”扩展得到多边形的性质:“n边形,n-1边之和要大于第n边”——>只需考虑比较极端的情况:第n边为最大值——>“n边之和大于两倍的最大边”。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main{
    public static boolean valid(int a,int b,int c){
        if(Math.abs(a-b)>=c)return false;
        if(Math.abs(b-c)>=a)return false;
        if(Math.abs(a-c)>=b)return false;
        if(a+b<=c)return false;
        if(b+c<=a)return false;
        if(c+a<=b)return false;
        return true;
    }
    public static void main(String []args){
        Scanner cin=new Scanner(System.in);
        while(cin.hasNext()){
            List<Integer>res=new ArrayList<Integer>();
            int n=cin.nextInt();
            for(int i=0;i<n;i++){
                int o=cin.nextInt();
                int l=cin.nextInt();
                if(o==1){
                    // 添加木棒
                    res.add(l);
                }else{
                    // 删除木棒
                    int idx=res.indexOf(l);
                    if(idx==-1){
                        System.out.println("No");
                        continue;
                    }
                    res.remove(idx);
                }
                int k=res.size();
                if(k>=4){
                    // 多边形的情况
                    int max=0;
                    int s=0;
                    for(int j=0;j<k;j++){
                        int tmp=res.get(j);
                        if(max<tmp)max=tmp;
                        s+=tmp;
                    }
                    if(s<=2*max)System.out.println("No");
                    else
                        System.out.println("Yes");
                }
                else if(k==3){
                    // 三角形的情况
                    int a=res.get(0);
                    int b=res.get(1);
                    int c=res.get(2);
                    if(valid(a,b,c))System.out.println("Yes");
                    else
                        System.out.println("No");
                }else
                    // 无法构成多边形
                    System.out.println("No");
            }
        }
    }
}

魔法权值

给出 n 个字符串,对于每个 n 个排列 p,按排列给出的顺序(p[0] , p[1] … p[n-1])依次连接这 n 个字符串都能得到一个长度为这些字符串长度之和的字符串。所以按照这个方法一共可以生成 n! 个字符串。
一个字符串的权值等于把这个字符串循环左移 i 次后得到的字符串仍和原字符串全等的数量,i 的取值为 [1 , 字符串长度]。求这些字符串最后生成的 n! 个字符串中权值为 K 的有多少个。
注:定义把一个串循环左移 1 次等价于把这个串的第一个字符移动到最后一个字符的后面。
输入描述:
每组测试用例仅包含一组数据,每组数据第一行为两个正整数 n, K , n 的大小不超过 8 , K 不超过 200。接下来有 n 行,每行一个长度不超过 20 且仅包含大写字母的字符串。
输出描述:
输出一个整数代表权值为 K 的字符串数量。
输入例子:
3 2
AB
RAAB
RA
输出例子:
3

思路

还没想出来。。。。。。。。

或与加

给定 x, k ,求满足 x + y = x | y 的第 k 小的正整数 y 。 | 是二进制的或(or)运算,例如 3 | 5 = 7。
比如当 x=5,k=1时返回 2,因为5+1=6 不等于 5|1=5,而 5+2=7 等于 5 | 2 = 7。
输入描述:
每组测试用例仅包含一组数据,每组数据为两个正整数 x , k。 满足 0 < x , k ≤ 2,000,000,000。
输出描述:
输出一个数y。
输入例子:
5 1
输出例子:
2

思路

0 0
x+y只要y不为0,则一定不等于x。而要使x|y!=x,则y的二进制中取1的位置必须至少有一个与x的二进制1的位置不同。且若y的二进制中取1的位置有1个与x相同,则x+y一定不等于x|y(因为相加会进位)。因此x+y=x|y要成立,则y的二进制中取1的位置必须与x中1的位置完全不同。
当x=5,k=1,则
x
0 1 0 1
y <—— k
0 0 1 0 <—— 01
1 0 0 0 <—— 10
1 0 1 0 <—— 11
由上可以看出,第k小正整数y的计算过程。首先令y=k,再根据x中1的位置对y进行扩展。(将y的值插入到x中不为1的位置,并将x中为1的位置置为0)
1、y=k=01
2、将y的值插入到x中不为1的位置,y=0 1 1 1
3、将x中为1的位置置为0,y=0 0 1 0

处理:
将k分为两个部分,low和high,low表示已经处理好的低位,high表示待处理的高位,low+high=k。从低到高遍历x的每一位,若x&1==0,则插入;若x&1==1,则待处理的高位先右移,即high<<=1,再插入。

#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
#include<string>
using namespace std;
int main(){
    long long x,k,y;
    while(cin>>x>>k){
        int tmp=1;
        while(x){
            // tmp=2^i,low为取k的低i位(低i位为二进制下标为0,1,2...(i-1))
            long long low=(tmp-1)&k;
            long long high=k-low;
            if(x&1){
                // 右移
                high<<=1;
            }
            // 插入
            k=high+low;
            tmp<<=1;
            x>>=1;
        }
        cout<<k<<endl;
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值