原题目地址: 牛客10道练习题2
发现有问题, 请提出来. 谢谢啦!
class Exam {
/**
* 一辆运送快递的货车,运送的快递均放在大小不等的长方体快递盒中,为了能够装载更多的快递,同时不能让货车超载,需要计算最多能装多少个快递。
* <p>
* 注:快递的体积不受限制,快递数最多1000个,货车载重最大50000。
*/
public static void t1() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入快递的重量, 用英文逗号分隔");
String weights = scanner.nextLine();
// 将输入的重量数据, 转成整数集合
int[] list = Arrays.stream(weights.split(",")).mapToInt(Integer::parseInt).toArray();
System.out.println("请输入货车的载重量: ");
int truckLoad = scanner.nextInt();
// 当前装货量 0
int sum = 0;
// 当前装货个数 0
int n = 0;
Arrays.sort(list);
for (int weight : list) {
// 先尝试装货
if ((sum += weight) > truckLoad) {
// 装货不成功, 输出当前装货量
System.out.println(n);
scanner.close();
return;
} else
// 装货成功, 则装货量 +1
n++;
}
System.out.println(n);
scanner.close();
}
/**
* 2、TLV解码
* <p>
* TLV编码是按[Tag Length Value]格式进行编码的,一段码流中的信元用Tag标识,Tag在码流中唯一不重复,Length表示信元Value的长度,Value表示信元的值。
* <p>
* 码流以某信元的Tag开头,Tag固定占一个字节,Length固定占两个字节,字节序为小端序。
* <p>
* 现给定TLV格式编码的码流,以及需要解码的信元Tag,请输出该信元的Value。
* <p>
* 输入码流的16机制字符中,不包括小写字母,且要求输出的16进制字符串中也不要包含小写字母;码流字符串的最大长度不超过50000个字节。
*/
public static void t2() {
Scanner scanner = new Scanner(System.in);
String tag = scanner.nextLine();
// 去除多余空格
tag = tag == null ? "" : tag.trim();
String codeStream = scanner.nextLine();
if (codeStream.length() > 50000) {
System.err.println("invalid input");
}
// 获取编码字符字数
String[] split = codeStream.split("\\s+");
// 记录每次tag
String TAG;
// 每次tag长度
int len;
for (int i = 0; i < split.length; i++) {
TAG = split[i];
len = Utils.littleEndianToInt(split[i + 1], split[i + 2]);
// 先将计时器置到这次编码的末尾
i += len + 2;
// 如果相等, 就输出value
if (tag.equals(TAG)) {
// String[] values = new String[len];
// // 提取value
// System.arraycopy(split, i - len + 1, values, 0, len);
// System.out.println(Utils.join(values, " "));
System.out.println(Utils.getRangeStr(split, i - len + 1, len, " "));
break;
}
}
scanner.close();
}
/**
* 3、考勤信息
*/
public static void t3() {
Scanner scanner = new Scanner(System.in);
// for (int i = 0; i <= 1; i++) {
//
// }
String s = "";
for (int i = 0; i < 2; i++) {
String[] split = scanner.nextLine().split("\\s+");
// 记录缺勤次数
int absentTimes = 0;
// 记录迟早或者早退次数
int lateAndLeaveearlyTimes = 0;
// 记录连续的迟到或者早退
boolean isContinuousLateAndLeaveearly = false;
// 连续考勤次数
int continuousPresentTimes = 0;
// 连续考勤次数
boolean isPresentTimesOk = false;
// 记录每个考勤是什么
String status;
for (int j = 0; j < split.length; j++) {
status = split[j];
if (Utils.isLateAndLeaveearly(status)) {
// 迟到早退+1
lateAndLeaveearlyTimes++;
if (j > 0 && Utils.isLateAndLeaveearly(split[j - 1])) {
// 上一次也是迟到早退, 连续的迟到和早退;
isContinuousLateAndLeaveearly = true;
}
// 不是连续考勤, 重置为0
continuousPresentTimes = 0;
} else if ("absent".equals(status)) {
// 缺勤+1
absentTimes++;
// 不是连续考勤, 重置为0
continuousPresentTimes = 0;
} else if ("present".equals(status)) {
// 连续考勤次数记录
if (++continuousPresentTimes >= 7) {
isPresentTimesOk = true;
}
}
}
/**
* 条件一: 缺勤不超过一次;
* 条件二: 没有连续的迟到/早退;
* 条件三: 任意连续7次考勤,缺勤/迟到/早退不超过3次
* -----------------------
* 一次考勤[present]:
* 条件一满足 条件二满足 条件三不满足 : 可以拿考勤奖励
*-------------------------------
* 两次缺勤[present absent present present leaveearly present absent]:
* 条件一不满足 条件二满足 条件三不满足: 不能拿考勤奖励
*
* 问题条件一满足 条件二不满足 条件三满足: 可否拿全勤奖励? 比如缺勤0次, 连续迟到早退2次, 连续7次考勤;
*
*/
// step1: 三个条件
if (absentTimes <= 1) {
// 缺勤少于1, 没有连续的迟到或者早退, 缺勤和早退不超过3次
if (!isContinuousLateAndLeaveearly && (absentTimes + lateAndLeaveearlyTimes <= 3)) {
s += true + " ";
continue;
}
}
s += false + " ";
}
System.out.println(s);
scanner.close();
}
/**
* 4、字符串分割
*/
public static void t4() {
char line = '-';
Scanner sc = new Scanner(System.in);
int k = sc.nextInt();
String s = sc.next();
int l = s.indexOf(line);
if (l == -1) {
System.out.println("");
return;
}
StringBuilder result = new StringBuilder(s.substring(0, l)); // 结果字符串, 先保留第一个字符串
StringBuilder temp = new StringBuilder(); // 字符缓存
int len;
// 大写字母个数缓存 和 小写字母个数缓存
int upperCaseNum = 0, lowerCaseNum = 0;
char c;
for (int i = l + 1, totalLen; i < (totalLen = s.length()); i++) {
c = s.charAt(i);
if (line != c) {
if (c > 95 && c < 123) {
lowerCaseNum++;
} else if (c > 64 && c < 91) {
upperCaseNum++;
}
temp.append(c);
// 当超过的时候, 就添加进
if ((len = temp.length()) >= k || i == totalLen - 1) {
result.append(line);
if (lowerCaseNum == upperCaseNum) {
result.append(temp);
} else if (lowerCaseNum > upperCaseNum) {
// 小写字母多, 小写
result.append(temp.toString().toLowerCase());
} else {
result.append(temp.toString().toUpperCase());
}
// 删除缓存操作
temp.delete(0, len);
lowerCaseNum = upperCaseNum = 0;
}
}
}
System.out.println(result.toString());
sc.close(); // 关闭输入器
}
/**
* 5、组成最大数
* “,”号分割的多个正整数字符串,不需要考虑非数字异常情况,小组最多25个人
*/
public static void t5() throws Exception {
Scanner sc = new Scanner(System.in);
String next = sc.nextLine();
String[] numbers = next.split(",");
int len = numbers.length;
if (len > 26) {
throw new Exception("Exceeding maximum number: 25");
}
String temp;
for (int i = 0; i < len - 1; i++) {
for (int j = i + 1; j > 0; j--) {
if (Utils.leftBig(numbers[j - 1], numbers[j])) {
break;
} else {
temp = numbers[j];
numbers[j] = numbers[j - 1];
numbers[j - 1] = temp;
}
}
}
System.out.println(Utils.join(numbers, ""));
}
/**
* 6. 高矮个子排队
* 现在有一队小朋友,他们高矮不同,我们以正整数数组表示这一队小朋友的身高,如数组{5,3,1,2,3}。
* <p>
* 我们现在希望小朋友排队,以“高”“矮”“高”“矮”顺序排列,每一个“高”位置的小朋友要比相邻的位置高或者相等;每一个“矮”位置的小朋友要比相邻的位置矮或者相等;
* <p>
* 要求小朋友们移动的距离和最小,第一个从“高”位开始排,输出最小移动距离即可。
* <p>
* 例如,在示范小队{5,3,1,2,3}中,{5, 1, 3, 2, 3}是排序结果。{5, 2, 3, 1, 3} 虽然也满足“高”“矮”“高”“矮”顺序排列,但小朋友们的移动距离大,所以不是最优结果。
* <p>
* 移动距离的定义如下所示:
* <p>
* 第二位小朋友移到第三位小朋友后面,移动距离为1,若移动到第四位小朋友后面,移动距离为2;
*/
public static void t6() {
// Scanner scanner = new Scanner(System.in);
// int[] arr;
// try {
// arr = Arrays.stream(scanner.nextLine().split("\\s+")).mapToInt(Integer::parseInt).toArray();
// } catch (Exception e) {
// System.out.println(Arrays.toString(new int[]{}));
// return;
// }
// flag: 0: 这次是要排矮的, 1: 这次要排高的 ; n : 交换次数
int flag = 0, n = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j > 0; j--) {
if (flag == 0) {
// 排矮, 高--矮
if (arr[i] < arr[j]) {
// 后面的高, 交换
swap(arr, i, j);
n++;
}
flag = 1;
} else {
// 排高的, 矮--高
if (arr[i] > arr[j]) {
// 后面的矮, 交换
swap(arr, i, j);
n++;
}
flag = 0;
}
break;
}
}
System.out.println("\n移动次数: " + n);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
/**
* 7、猴子爬山
* <p>
* 一天一只顽猴想去从山脚爬到山顶,途中经过一个有个N个台阶的阶梯,但是这猴子有一个习惯: 每一次只能跳1步或跳3步,试问猴子通过这个阶梯有多少种不同的跳跃方式?
* <p>
* 1: t(n) = t(n-1) + t(n-3); n >= 3, n∈Z;
* 2: n=3, sum=2; n=2, sum=1; n=1,sum=1;n=0, sum=0;
*/
public static void t7(int N) {
// if (N > 50 || N < 0) {
//
// System.err.println("invalid input");
// return;
// }
// 非递归缓存版
int[] sums = new int[N + 1];
sums[0] = 0;
sums[1] = sums[2] = 1;
sums[3] = 2;
for (int i = 4; i <= N; i++)
sums[i] = sums[i - 1] + sums[i - 3];
System.out.println(sums[N]);
int[] sums1 = new int[N + 1];
// 递归缓存版
t7Recursion(N, sums1);
System.out.println(sums1[N]);
// 缓存版
System.out.println(t7Swap(N));
}
// t7 递归版
public static int t7Recursion(int N, int[] sums1) {
if (N == 1 || N == 2) {
sums1[N] = 1;
return 1;
} else if (N == 3) {
sums1[N] = 2;
return 2;
}
if (sums1[N] == 0)
sums1[N] = t7Recursion(N - 1, sums1) + t7Recursion(N - 3, sums1);
return sums1[N];
}
// t7 交换版
public static int t7Swap(int N) {
int step1 = 1;
int step2 = 1;
int step3 = 2;
int stepTemp;
if (N == 1 || N == 2) {
return 1;
} else if (N == 3) {
return 2;
}
for (int i = 4; i <= N; i++) {
stepTemp = step1 + step3;
step1 = step2;
step2 = step3;
step3 = stepTemp;
}
return step3;
}
/**
* 小明从糖果盒中随意抓一把糖果,每次小明会取出一半的糖果分给同学们。
* <p>
* 当糖果不能平均分配时,小明可以选择从糖果盒中(假设盒中糖果足够)取出一个糖果或放回一个糖果。
* <p>
* 小明最少需要多少次(取出、放回和平均分配均记一次),能将手中糖果分至只剩一颗
*/
public static long t8(long l) {
// Scanner scanner = new Scanner(System.in);
// long l = scanner.nextLong();
if (l >= 10000000000L) {
System.err.println("invalid input");
return 0;
}
String s;
int len;
int n = 0; // 分的次数
int i;
while (l != 1) {
s = Long.toBinaryString(l);
len = s.length();
// System.out.println(l + " " + s);
i = 1;
while ('0' == s.charAt(len - i++)) { // 1.......0 -> 减少一位
l /= 2;
n++;
}
if ('1' == s.charAt(len - 1)) {
if (l == 3 || '0' == s.charAt(len - 2)) {
l--;
// 1..........01 -> 1...........100 下次一定会减少两位
} else {
l++;
// 1..........11 -> 1............100 下次一定会减少两位
}
n++;
}
}
return n;
}
/**
* 100个人围成一圈,每个人有一个编码,编号从1开始到100。他们从1开始依次报数,
* 报到为M的人自动退出圈圈,然后下一个人接着从1开始报数,直到剩余的人数小于M。请问最后剩余的人在原先的编号为多少?
*/
public static void t9(int M) {
int max = 100; // 100人
if (M <= 1 || M >= max) {
System.out.println("ERROR!");
return;
}
// 非链表版, 测试了一下数组遍历是相当的快.
Boolean[] alive = new Boolean[max];
// 一共100人
int aliveNum = max;
// 复活所有人
Arrays.fill(alive, true);
// 当前报数下标
int index = -1;
// 报数计数器 1234...m
int count = 0;
while (aliveNum >= M) {
index = ++index >= max ? index - max : index;
// 活人报数, 等于M就退出
if (alive[index] && ++count == M) {
// 先退出游戏
alive[index] = false;
// 在重置报数
count = 0;
// 活人减1
aliveNum--;
}
}
String result = "";
for (int i = 0; i < max; i++) {
if (alive[i]) {
result += (i + 1) + ",";
}
}
System.out.println(result.substring(0, result.length() - 1));
}
/**
* 10、消消乐游戏
* 消消乐游戏
* 游戏规则:输入一个只包含英文字母的字符串,字符串中的两个字母如果相邻且相同,就可以消除。
* <p>
* 在字符串上反复执行消除的动作,直到无法继续消除为止,此时游戏结束。
* <p>
* 输出最终得到的字符串长度。
* <p>
* 输入描述:
* 输入原始字符串 str ,只能包含大小写英文字母,字母的大小写敏感, str 长度不超过100。
* <p>
* 输出描述:
* 输出游戏结束后,最终得到的字符串长度
*/
public static void t10(String s) {
int len = s.length();
LinkedList<Character> deque = new LinkedList<>();
for (int i = 0; i < len; i++) {
if (i > 0 && deque.size() > 0 && deque.getLast() == s.charAt(i)) {
// 如果和栈尾相同, 则消除
deque.pollLast();
} else {
// 进栈
deque.add(s.charAt(i));
}
}
System.out.println(deque.size());
}
}
帮助工具(有时候忘记了轮子, 就会重复造轮子, 如果你记得, 那你就不用下面的工具方法哦):
class Utils {
protected static int listSum(List<Integer> list) {
int sum = 0;
for (int i = 0; i < list.size(); i++) {
sum += list.get(i);
}
return sum;
}
protected static int arrSum(int[] list) {
int sum = 0;
for (int i = 0; i < list.length; i++) {
sum += list[i];
}
return sum;
}
/**
* 判断状态是不是迟到或者早退
*
* @param status 考勤状态
* @return bool
*/
protected static boolean isLateAndLeaveearly(String status) {
return "late".equals(status) || "leaveearly".equals(status);
}
protected static void outAndCloseScanner(Object object, Scanner scanner) {
System.out.println(object);
if (scanner != null) {
scanner.close();
}
}
protected static boolean leftBig(String a, String b) {
return Double.parseDouble(a + b) > Double.parseDouble(b + a);
}
/**
* 用字符连接集合的内容, 返回连接后的内容字符串
*
* @param list 数组
* @param o 连接字符
* @return 连接后的内容
*/
protected static String join(@NotNull List<String> list, @NotNull String o) {
int len = list.size();
if (len == 0) {
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) {
sb.append(list.get(i)).append(o);
}
return sb.substring(0, sb.length() - 1);
}
/**
* 用字符连接数组的内容, 返回连接后的内容字符串
*
* @param arr 数组
* @param o 连接字符
* @return 连接后的内容
*/
protected static String join(@NotNull Object[] arr, @NotNull String o) {
int len = arr.length;
if (len == 0) {
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) {
sb.append(arr[i]).append(o);
}
return sb.substring(0, sb.length() - 1);
}
/**
* @param num
* @param lower 下界
* @param upper 上界
* @return boolean
*/
protected static boolean isBetweenAnd(int num, int lower, int upper) {
if (lower < num && num < upper) {
return true;
}
return false;
}
/**
* 小端序字符转10进制数
*
* @param littleEndians 小端字节序
* @return 转化后的十进制数
*/
protected static int littleEndianToInt(@NotNull String... littleEndians) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = littleEndians.length - 1; i > -1; i--) {
stringBuilder.append(littleEndians[i]);
}
return Integer.parseInt(stringBuilder.toString(), 16);
}
/**
* 用字符串连接数组中范围内的内容, 返回新的内容字符串.
*
* @param arr 内容数组
* @param i 开始下标
* @param len 长度
* @param o 连接字符
* @return 内容字符串
*/
protected static String getRangeStr(String[] arr, int i, int len, String o) {
int index = i;
int length = arr.length;
if (length == 0) {
return "";
}
StringBuilder sb = new StringBuilder();
for (; i < index + len; i++) {
sb.append(arr[i]).append(o);
}
return sb.deleteCharAt(sb.length() - 1).toString();
}
/**
* 磁盘容器字典
*/
protected static Map<Character, Integer> diskCapacityMap = new ConcurrentHashMap<Character, Integer>() {{
put('M', 1);
put('G', 1024);
put('T', 1024 * 1024);
}};
/**
* 将容量数据实体化, 转换为int数字, 单位是M.
*
* @param diskCapacity 容量数据
* @return
*/
protected static int conversionDiskCapacityToM(@NotNull String diskCapacity) {
int len = diskCapacity.length();
if (len == 0) {
return 0;
}
Set<Character> characters = diskCapacityMap.keySet();
int result = 0;
Character temp;
int o = 0;
for (int i = 0; i < len; i++) {
temp = diskCapacity.charAt(i);
if (characters.contains(temp)) {
result += Integer.parseInt(diskCapacity.substring(o, i)) * diskCapacityMap.get(temp);
o = i + 1;
}
}
return result;
}
}
测试demo
// Exam.t1();
// Exam.t2();
// Exam.t3();
// Exam.t4();
// Exam.t5();
// Exam.t7(3);
// Exam.t7(50);
// Exam.t7(81); // 已经超出int的最大值, 所以爆掉了
// System.out.println(Exam.t8(13));
// System.out.println(Exam.t8(10));
// System.out.println(Exam.t8(17));
// System.out.println(Exam.t8(87654367));
// for (int i = 3; i < 1000000; i += 2) {
// if (Exam.t8(i) - 1 != Math.min(Exam.t8(i - 1), Exam.t8(i + 1))) {
// System.out.println(i);
// }
// }
// Exam.t9(3);
// Exam.t9(4);
// Exam.t9(5);
// Exam.t10("MMM");
如果有问题, 请及时提出来哦~ 谢谢啦.
一起进步~