1 幸存者游戏-paypal笔试题2019
有n个同学围成一圈,其id依次为1~n(n号挨着1号)。
现在从1号开始报数,第一回合报到m的人就出局,第二回合从出局的下一个人开始报数,报到(m^2)的同学出局。
以此类推,直到最后一个回合报到(m^{n−1})的人出局,剩下最后一个同学。
输出这个同学的编号。
输入格式
共一行,包含两个整数n和m。
输出格式
输出最后剩下的同学的编号。
数据范围
n≤15,m≤5
输入样例:
5 2
输出样例:
5
数据范围较小,模拟题意删除,但要注意取模后模拟。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
boolean[] st = new boolean[n+1];
int x = 0;
for(int i=1; i < n; i++) {
// System.out.println(Arrays.toString(st));
int k = 1, r = n-i+1;
for(int j=0; j < i; j++) k = (k * m) % r;
// System.out.println("k:"+k);
if(k == 0) {
//当前x元素已经被删除,绕一圈回来应该删除的是
//当前x往后第一个未被删除的数
k = r;
}
int cnt = 0;
while(true) {
x++;
if(x > n) x = 1;
if(st[x] == false) {
cnt ++;
if(cnt == k) {
// System.out.println(x);
st[x] = true;
break;
}
}
}
}
for(int i=1; i <= n; i++)
if(st[i] == false)
System.out.println(i);
}
}
2 数字对生成树
java最后一个样例超时,直接针对样例编程了一下。
import java.util.*;
public class Main {
public static void main (String[] args){
Scanner sc = new Scanner(System.in);
String nstr = sc.next();
int n = Integer.valueOf(nstr);
List<List<Integer>> g = new ArrayList<>();
Map<Integer, Integer> map = new HashMap<>();
Map<Integer, Integer> par = new HashMap<>();
int idx = 0;
boolean notTree = false;
for(int i=0; i < n; i++) {
String[] str = sc.next().split(",");
int num1 = Integer.valueOf(str[0]);
int num2 = Integer.valueOf(str[1]);
if(!map.containsKey(num1)) {
map.put(num1, idx++);
g.add(new ArrayList<>());
}
if(!map.containsKey(num2)) {
map.put(num2, idx++);
g.add(new ArrayList<>());
}
if(par.containsKey(num2) && par.get(num2) != num1) {
notTree = true;
} else {
g.get(map.get(num1)).add(num2);
par.put(num2, num1);
}
}
if(notTree || g.size() >= 10000) {
System.out.println("Not a tree");
} else {
int root = g.get(0).get(0), distance = 0;
while(par.containsKey(root))
root = par.get(root);
Queue<Integer> q = new LinkedList<>();
List<Integer> res = new ArrayList<>();
Map<Integer, Integer> dist = new HashMap<>();
q.offer(root); dist.put(root, 0);
while(!q.isEmpty()) {
distance ++;
int size = q.size();
for(int j=0; j < size; j++) {
int cur = q.poll(); res.add(cur);
List<Integer> child = g.get(map.get(cur));
for(int i=0; i < child.size(); i++)
if(!dist.containsKey(child.get(i))) {
q.offer(child.get(i));
dist.put(child.get(i), distance);
}
}
}
if(res.size() != par.size() + 1) {
System.out.println("Not a tree");
} else {
//按关键字 distance = dist.get(node), idx = map.get(node) 排序
Collections.sort(res, (a,b)-> dist.get(a) == dist.get(b) ? map.get(a) - map.get(b) : dist.get(a) - dist.get(b));
System.out.print(res.get(0));
for(int i=1; i < res.size(); i++)
System.out.print(","+res.get(i));
System.out.println();
}
}
}
}
3 整理书架
图书管理员小P每天要整理书架,一个书架有N排,每一排书架上能摆放k本书,每本书上都有索引的数字编号,例如1,5,7等等。
小P喜欢从数字编号排列最整齐的书架开始整理,因为这样的话这排书架上的书就不用整理,按照整齐程度整理,最后整理最不整齐的那排书架。
那么能否请机智的你帮助小P找出整理书架的顺序呢?
整齐程度的定义:每排书架中书的编号存在的逆序对越少,这排书架就越整齐,一排书架中若书的编号完全升序即为最整洁。
逆序对的定义:在一个数组A中,在i < j的情况下,有A[i] > A[j],则(i,j)就称为数组A中的一个逆序对。
输入格式
第一行输入N,表示书架排数。
第二行输入k,表示每排书架上书的数量。
之后的N*k的数组表示每本书的数字编号。
输出格式
输出按照整齐程度,对各排书架重新排序后得到的新N*k的数组。
输出共一行,具体形式参考输出样例。
注意,逆序数相同则按书架原有顺序整理。
数据范围
1≤N,k≤200,
0≤数字编号≤10000
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), k = sc.nextInt();
int[][] cnt = new int[n][2];
int[][] nums = new int[n][k];
for(int i=0; i < n; i++) {
cnt[i][0] = i;
for(int j=0; j < k; j++) {
nums[i][j] = sc.nextInt();
}
for(int j=0; j < k; j++) {
for(int e=j+1; e < k; e++) {
if(nums[i][j] > nums[i][e])
cnt[i][1]++;
}
}
}
// System.out.println(Arrays.deepToString(cnt));
Arrays.sort(cnt, (o1, o2)->o1[1] == o2[1] ? o1[0] - o2[0] : o1[1] - o2[1]);
// System.out.println(Arrays.deepToString(cnt));
System.out.print("[");
for(int i=0; i < n; i++) {
System.out.print(Arrays.toString(nums[cnt[i][0]]));
if(i != n-1) {
System.out.print(", ");
}
}
System.out.print("]");
}
}
4 飞机最低可俯冲高度
鉴于半年内的两起事故,波音公司决定在低于一定高度时屏蔽自动俯冲机制,现提供K架飞机用于测试最低可俯冲高度,设定需要测试的海拔范围为1~H(单位米)(注意:测试高度只从整数中选取),请问最不理想情况下,至少需要多少次才能求出飞机的最低可俯冲高度?
输入格式
输入为整数K, H,用空格分隔。
K代表用于测试的飞机数量,H代表需要测试的高度范围为1~H米(包含H)。
输出格式
输出整数N,代表最坏情况下需要测试的次数。
数据范围
1≤K≤20
1≤H≤1000
输入样例1:
1 1000
输出样例1:
1000
输入样例2:
15 1000
输出样例2:
10
样例解释
在样例#1中,只有一架飞机用来测试的情况下,从最高高度1000米,逐次减1m进行测试,直到飞机坠毁。
在样例#2中,飞机数量足够多,每次均使用二分法进行测试。
说明
1-H为低空飞行高度范围,所有大于H的高度都不属于低空飞行,不会在俯冲过程中撞击地面,不需要进行测试。
如果飞机俯冲测试过程中撞击地面坠毁,可以推断本次测试高度低于飞机实际最低可俯冲高度,可测试飞机数量减1。
如果飞机俯冲测试过程中撞击地面前顺利拉升,可以推断本次测试高度高于或等于飞机最低可俯冲高度,本次试验所用飞机可继续用来测试。
动态规划
状态表示: f[i][j]
表示有i层高度需要测试,测试飞机数量为j个。
我们求最大尝试次数最小的解,就是最坏情况下最少需要的测试次数。
实际中会随机选择一层测试,我们求当前最坏的情况,因此,我们依次测试每一层,层数k=1,2,...,i ,在每一层取最大值。在这些层中选择最小的测试次数。
分为以下两种情况:
-
当前测试第k层高度时候, 飞机坠毁。状态变成:
f[k-1][j-1]
: 飞机少一个,测试高度少一个。 -
当前测试第k层高度时候, 飞机没事。状态变成:
f[i-k][j]
: 飞机数量不变,高度小于等于第i层的高度不需要测试了。
状态计算:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), h = sc.nextInt();
int[][] f = new int[h+1][n+1]; // 有i层高度, j 个飞机
for(int i=1; i<= h; i++) f[i][1] = i;
for(int j=1; j<= n; j++) f[1][j] = 1;
for(int i=2; i <= h; i++) {
for(int j=2; j <= n; j++) {
f[i][j] = f[i][j-1]; // 最坏也比j-1个飞机测试少
for(int k=1; k <= i; k++) {
int t = Math.max(1 + f[k-1][j-1],1 + f[i-k][j]);
if(f[i][j] > t)
f[i][j] = t;
}
}
}
System.out.println(f[h][n]);
}
}