字节跳动-2020秋招-笔试题剖析【5道算法题】,限时120分钟。 抖音上不同的用户类型我们有不同的用户模型文件。 给定一行输入,格式是a b 注意1:每个模型文件可能对应多个用户类型,用户类型之间用空格作为切分。 输入第1行: 用户类型 N(表示有多少个 用户类型) 模型文件用户类型1 用户类型2 输入: 1 输出: 1.txt abc 旅行者穿越沙漠的过程中需要不断地消耗携带的饮用水,到达终点前会经过几个绿洲,每个绿洲均设有水分补给站可以为旅行者提供水分补给并收取一定的费用。 沿途共有n个补给站,每个补给站收取的费用都一样,但是提供的水量不尽相同。起点到终点的距离为D公里,postion[i]表示第i个补给站距离起点的距离,单位为公里,supply[i]表示第i 个补给站可以提供的水量,单位为升。 假设旅行者在起点时携带了W升的水,每行走1公里需要消耗1升的水量,身上可携带的水量没有上限,且携带的水量多少不会对体能消耗产生影响,鉴于每次进补给站花费的钱都是一样多,期望用最少的补给次数到达终点,请帮忙计算最少的补给次数。 第一行输入整数D和W, D表示起点到终点的距离,W表示初始携带的水量 第二行输入数组postion,长度为N,分别表示N个补给站分别距离起点的距离 第三行输入数组supply,长度为N, 分别表示N个补给站分别可以供给的水量 数据范围:1 <= D, W<=10^8, 0<=N<=1000, 0<position[i],supply[i]<D 输出一个整数表示最少的补给次数,若无法到达终点则返回-1 输入: 10 4 输出: 1 说明: 给定一个迷宫,找到最快从起点到达重点的路径所需要的步数。 每一行输入都是用空格隔开的整数 输出最少要多少步能够从起点走到终点。 输入: 4 3 输出: 3 说明: 春节在家的凯凯真的是太无聊了,他准备和他家的猫玩一个游戏。 首先输入一个数字t,表示有t组数据 对于每组数据输出YES 或者 NO 输入: 2 输出: YES 说明: 你有n种无门槛优惠券,每种优惠券有一个面值ai。当一件商品的售价≥ai时,你可以出示这种优惠券直接抵扣。抵扣后,优惠券不会被回收,可以继续使用。现在,你想要买m件商品,每件商品的售价是bi,请问你最少需要花费多少钱? 第一行两个正整数n,m(1≤n,m≤10^6) 第二行n个正整数ai (0≤ai≤10^6),代表n种无门槛优惠券的面值 (不保证排序) 输出合理使用优惠券后,购买上述m件商品最少需要的花费。 输入: 3 4 输出: 248
让我们一起来看看这些题吧!
题一:模型文件去重
【题目描述】
我们有一个模型配置文件,里面有很多的不同的用户类型和他们对应的模型文件。我们需要找出每个模型对应的是哪些用户类型。
a表示这个用户的用户类型,b表示这个用户对应的模型文件。
请你输出每个模型文件对应的用户类型。
注意2: 如果有多个用户类型输出,用户类型之间的排序按照字母表排序。
注意3: 如果有多个模型输出,模型输出的顺序按照模型文件在输入数据中顺序,即从上到下。【输入描述】
接下来的N行:用户类型 模型文件【输出描述】
【示例】
abc 1.txt【解决思路及要点】
【解决代码】
public class Solution1 { public static void main(String[] args) { List<String> model=new ArrayList<>(); Map<String,Set<String>> table=new HashMap<>(); Scanner sc=new Scanner(System.in); int n=sc.nextInt(); String a=new String(); String b=new String(); while(n-->0){ a=sc.next(); b=sc.next(); if(!table.containsKey(b)){ model.add(b); table.put(b, new HashSet<String>()); } table.get(b).add(a); } for(String m:model){ System.out.print(m); for(String consumer:table.get(b)){ System.out.print(" "+consumer); } System.out.print("n"); } } }
【题目剖析】
题二:穿越沙漠的补给次数
【题目描述】
【输入描述】
【输出描述】
【示例】
1 4 7
6 3 5
每行输入用空格隔开。起点到终点共10公里,初始时携带4升水,途径3个补给站。共需补给一次:只需在第1个补给站补给一次获得6升水,即可走完全程。【解决思路及要点】
【解决代码】
public class Solution2 { public static int minCount(int D,int W,int[] position,int[] supply){ int ans=0; int n=position.length; //标记数组,true代表已经取过水了 boolean[] flag=new boolean[n]; //当前所在位置 int currPos=0; while(currPos<D){ //每次都把水喝完 currPos+=W; W=0; //如果走完,直接返回 if(currPos>=D){ return ans; } //记录能获得最多水的下标 int maxWater=-1; for(int i=0;i<n;i++){ //还未达到相应的补给站 if(position[i]>currPos){ break; } //如果如果还没从该水站取水,就看在这里取水能否得到最大的水量 if(!flag[i]&&supply[i]>W){ W=supply[i]; maxWater=i; } } //此时无水,并且没有可以取水的水站,无法到达 if(maxWater==-1){ return -1; } flag[maxWater]=true; ans++; } return ans; } public static void main(String[] args) { Scanner sc=new Scanner(System.in); int D=sc.nextInt(); int W=sc.nextInt(); sc.nextLine(); String s = sc.nextLine(); String[] s1 = s.split(" "); int n=s1.length; int[] position=new int[n]; int[] supply=new int[n]; for (int i = 0; i < n; i++) { position[i]=Integer.valueOf(s1[i]); } s = sc.nextLine(); String[] s2 = s.split(" "); for (int i = 0; i < n; i++) { supply[i]=Integer.valueOf(s2[i]); } System.out.println(minCount(D,W,position,supply)); } }
【题目剖析】
题三:走迷宫
【题目描述】
假设迷宫如下,假定左上角坐标为(0,0),右下角坐标为 (3,2)
1 0 -1 1
-2 0 -1 -3
2 2 0 0
-2是迷宫的起点,坐标为(0,1)
-3是迷宫的终点,坐标为(3,1)
-1代表障碍物,不能行走
1和2代表传送门,传送门由正整数标示,只会成对出现。站在传送门上,能仅用一步就传送到相同数字的另一个传送门的位置:1只能传送到1,2只能传送到2。站在传送门上也可以选择不传送。
从起点到终点有若干种走法,举例如下:
(0,1)->(1,1)->(1,2)->(2,2)->(3,2)->(3,1),共花费5步
或者
(0,1)->(0,0)-传送>(3,0)->(3,1),共花费3步
经检验3步是所需的最少步数,最后结果返回3【输入描述】
第一行给出迷宫地图的长和宽,均为正整数
之后每一行的每一个数字,都代表迷宫的一格
-2表示起点,-3表示终点,-1表示不可通过的障碍物,0表示可通过的道路,大于0的正整数代表传送门,并且保证成对出现,在传送门上,可以仅用一步传送到另一个相同数字的传送门的位置。
迷宫大小<=200*200【输出描述】
输出-1如果没有任何办法从起点走到终点。【示例】
1 0 -1 1
-2 0 -1 -3
2 2 0 0
(0,1)->(0,0)-传送>(3,0)->(3,1) ,共花费3步【解决思路及要点】
【解决代码】
public class Solution3 { public static void main(String[] args) { Scanner sc=new Scanner(System.in); //获取长宽 String[] dimension = sc.nextLine().split(" "); int width = Integer.valueOf(dimension[0]); int height = Integer.valueOf(dimension[1]); //迷宫 Square[][] map = new Square[width][height]; //一个y对应底图的一列 int y = 0; //起始点和终点 Square start = null; Square end = null; //传送门对应的哈希表 Map<Integer, WarpGate> warpGate = new HashMap<>(); //获取地图,同时初始化相关的类 while (y<height) { String line = sc.nextLine(); String[] squares = line.split(" "); for (int x = 0; x < width; x++) { map[x][y] = new Square(x, y, Integer.valueOf(squares[x])); if (map[x][y].type == Square.SQUARE_START) { start = map[x][y]; } else if (map[x][y].type == Square.SQUARE_END) { end = map[x][y]; } else if (map[x][y].isWarpGate()) { //建立传送门 int gateNumber = map[x][y].type; WarpGate wg = warpGate.get(gateNumber); if (wg == null) { wg = new WarpGate(); warpGate.put(gateNumber, wg); } wg.buildWarpGate(map[x][y]); } } y++; } if (start == null || end == null) { throw new RuntimeException("未发现起始点或者终点!"); } //迷宫创建成功,开始运算 System.out.println(solve(start, end, map, warpGate)); } //走迷宫核心代码 public static int solve(Square start, Square end, Square[][] map, Map<Integer, WarpGate> warpGate) { //标志是否访问过 Set<State> visited = new HashSet<>(); //BFS队列 Set<State> queue = new LinkedHashSet<>(); //放入起始点 queue.add(new State(start, 0)); while(!queue.isEmpty()) { Iterator<State> currentIt = queue.iterator(); //获取当前当前走的点 State current = currentIt.next(); currentIt.remove(); //走到终点 if (current.square.equals(end)) { return current.step; } //更新标志 visited.add(current); //寻找下一个要走的点 current.nextStates(map, queue, visited, warpGate); } return -1; } //迷宫中的一个点 public static class Square { public final int x; public final int y; public final int type;//这个点的类型 //题目中可能的类型 public static final int SQUARE_START = -2; public static final int SQUARE_END = -3; public static final int SQUARE_PATH = 0; public static final int SQUARE_BLOCK = -1; public Square(int x,int y,int type){ this.x = x; this.y = y; this.type = type; } //提供专门判断是否是传送门的方法 public boolean isWarpGate() { return type > 0; } @Override public int hashCode() { return Objects.hash(x, y); } } //传送门类 public static class WarpGate{ public Square s1; public Square s2; //获取传送到的点,不是s1或者s2就返回null public Square getOtherSide(Square s) { if (s.equals(s1)) { return s2; } else if (s.equals(s2)) { return s1; } else { return null; } } //建立一个传送门 public void buildWarpGate(Square s) { if (s1 == null) { s1 = s; } else if (s2 == null) { s2 = s; } else { throw new RuntimeException("建立传送门异常!"); } } } //一个点的状态 public static class State{ public final Square square; public int step; public State(Square square, int step) { this.square = square; this.step = step; } //更新到下一个未访问过的点 public void nextStates(Square[][] map, Set<State> toVisit, Set<State> visited, Map<Integer, WarpGate> warpGate){ //左边的点存在,尝试加入队列 if (square.x > 0) { Square left = map[square.x - 1][square.y]; addUnvisitedStateToList(left, toVisit, visited); } //右边的点存在,尝试加入队列 if (square.x < map.length - 1) { Square right = map[square.x + 1][square.y]; addUnvisitedStateToList(right, toVisit, visited); } //下边的点存在,尝试加入队列 if (square.y > 0) { Square up = map[square.x][square.y - 1]; addUnvisitedStateToList(up, toVisit, visited); } //上边的点存在,尝试加入队列 if (square.y < map[0].length - 1) { Square down = map[square.x][square.y + 1]; addUnvisitedStateToList(down, toVisit, visited); } //尝试走传送门 WarpGate gate = warpGate.get(square.type); if (gate != null) { addUnvisitedStateToList(gate.getOtherSide(square), toVisit, visited); } } private void addUnvisitedStateToList(Square s, Set<State> toVisit, Set<State> visited) { State resultState = new State(s, this.step + 1); //满足条件的点加入队列 if (s.type != Square.SQUARE_BLOCK && !visited.contains(resultState) && !toVisit.contains(resultState)) { toVisit.add(resultState); } } } }
【题目剖析】
题四:简单变换
【题目描述】
凯凯在黑板上写下了两个长度相等的数列a[1…n], b[1…n]。
现在他想让他的猫判断数列a能否通过一个操作变换成数列b。
这个操作是:在数列a中选择一个区间l-r,对这个区间所有的数字加上一个k。
其中1<=l<=r<=n, k>=0。
你可以帮帮可怜的小猫做出这个判断么?【输入描述】
每组数据的第一行为一个数字n 表示数列的长度
接下来两行每行有n个数字,分别为数组a和数组b
t<=10
n<=100000【输出描述】
表示数列a能否通过对应的操作变换成数列b。【示例】
6
3 7 1 4 1 2
3 7 3 6 3 2
5
1 1 1 1 1
1 2 1 3 1
NO
对于第一个样例可以对区间[1,4,1] 的每个数字加上2,即可把数列a转换成数列b
对于第二个样例没法做相应的操作【解决思路及要点】
【解决代码】
public class Solution4 { public static void main(String[] args) { Scanner sc=new Scanner(System.in); int t=sc.nextInt(); while(t-->0){ int n=sc.nextInt(); int[] a=new int[n]; int[] b=new int[n]; for(int i=0;i<n;i++){ a[i]=sc.nextInt(); } for(int i=0;i<n;i++){ b[i]=sc.nextInt(); } //差分数组 for (int i = 0; i < n; ++i){ a[i] = b[i] - a[i]; } //左右指针 int left=-1,right=-1; int k=0; //标记是否成功转换 boolean flag=true; for(int i=0;i<n;i++){ //a[i]属于相等的部分 if(a[i]!=0){ //更新左指针 if(left==-1){ left=i; } //更新右指针 if (right == -1 || right == i - 1){ right=i; }else if(right!=-1 && right!=i-1){ //此时若右指针不在初始位置并且不在i-1的位置,说明需要转换的地方不连续,无法进行转换操作 System.out.println("NO"); flag=false; break; } }else if(a[i]<0){ //此时说明数组b需要加,对a操作不可能转换 System.out.println("NO"); flag=false; break; }else if(a[i]>0){ //a数组要加,如果k不是初始值,也不和a[i]相等,也无法转换 if(k!=0 && k!=a[i]){ System.out.println("NO"); flag=false; break; } k=a[i]; } } if(flag){ System.out.println("YES"); } } } }
【题目剖析】
题五:优惠券
【题目描述】
【输入描述】
第三行m个正整数bi (0≤bi ≤10^6),代表m件商品的价格 (不保证排序)【输出描述】
【示例】
50 100 200
99 199 200 300【解决思路及要点】
【解决代码】
public class Solution5 { public static void main(String[] args) { Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int m=sc.nextInt(); int[] a=new int[n]; for(int i=0;i<n;i++){ a[i]=sc.nextInt(); } Arrays.sort(a); long ans=0; while(m-->0){ int price=sc.nextInt(); int index=Arrays.binarySearch(a,price); //注意二分搜索的返回值 if(index<0){ index=-index-2; } ans+=price-a[index]; } System.out.println(ans); } }
【题目剖析】
该次笔试题感悟:
本文全部代码已上传至github仓库,欢迎大家Star一波!
链接:https://github.com/ATFWUS/Algorithm-Pen-Test-2020/tree/master/%E5%AD%97%E8%8A%82%E8%B7%B3%E5%8A%A8%E7%A7%8B%E6%8B%9B%E7%AC%94%E8%AF%95%E9%A2%98
ATFWUS
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算