牛客网十道题目2

原题目地址: 牛客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");

如果有问题, 请及时提出来哦~ 谢谢啦.


一起进步~
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值