牛客10道练习题2--练习记录

这篇博客涵盖了多种算法的应用,包括货车装载快递的最大数量计算、考勤信息判断、字符串分割与转换、数字组合优化、高矮个子排队问题、猴子爬山问题、分糖果问题、报数游戏以及消消乐游戏的解决方案。涉及到排序、字符串操作、动态规划、双指针等算法思想。

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

原题:牛客10道练习题2_meiribaofu的博客-CSDN博客

1、快递运输

一辆运送快递的货车,运送的快递均放在大小不等的长方体快递盒中,为了能够装载更多的快递,同时不能让货车超载,需要计算最多能装多少个快递。

输入描述:

第一行输入每个快递的重量,用英文逗号分隔,如:5,10,2,11

第二行输入货车的载重量,如:20

不需要考虑异常输入。

输出描述:

输出最多能装多少个快递,如:3

    public static int delivery(int[] arr, int weight) {
        Arrays.sort(arr);
        int sum = Arrays.stream(arr).sum(); //快递总重量
        int sums = 0;
        //sum - sums[i] = sums //去掉某个快递的剩余重量
        for (int i = arr.length - 1; i >= 0; i--) {
            if (sum - sums < weight) {
                return i + 1;
            } else {
                sums += arr[i];
            }
        }
        return 0;
    }

(没有第二题,因为题目看不懂QAQ)

3、考勤信息

公司用一个字符串来表示员工的出勤信息:

absent:缺勤

late:迟到

leaveearly:早退

present:正常上班

现需根据员工出勤信息,判断本次是否能获得出勤奖,能获得出勤奖的条件如下:

缺勤不超过一次;没有连续的迟到/早退;任意连续7次考勤,缺勤/迟到/早退不超过3次

present

present absent present present leaveearly present absent

输出描述:

根据考勤数据字符串,如果能得到考勤奖,输出"true";否则输出"false",对于输入示例的结果应为:

true false

    public static boolean fullAttendance(String str) {
        Stack<String> stack = new Stack<>();
        Queue<String> queue = new LinkedList<>();
        String[] s = str.split(" ");
        int absent = 0;
        int count = 0;
        for (int i = 0; i < s.length; i++) {
            String cur = s[i];
            if (cur.equals("absent")) {
                if (++absent > 1) return false;
            }
            //用栈判断是否有连续的早退或迟到
            if (cur.equals("leaveearly") || cur.equals("late")) {
                if (stack.peek().equals("late") || stack.peek().equals("leaveearly")) {
                    return false;
                } else {
                    count++;
                }
            }
            stack.push(cur);
            queue.offer(cur);
            //队列7次判断是否三次以上迟到或早退,否则出队一个保证任意7天
            if (queue.size() == 7 && count > 3) {
                return false;
            } else {
                String poll = queue.poll();
                if (poll.equals("late") || poll.equals("leaveearly")) {
                    count--;
                }
            }
        }
        return true;
    }

4、字符串分割

给定一个非空字符串S,其被N个‘-’分隔成N+1的子串,给定正整数K,要求除第一个子串外,其余的子串每K个字符组成新的子串,并用‘-’分隔。对于新组成的每一个子串,如果它含有的小写字母比大写字母多,则将这个子串的所有大写字母转换为小写字母;反之,如果它含有的大写字母比小写字母多,则将这个子串的所有小写字母转换为大写字母;大小写字母的数量相等时,不做转换。

输入描述:

输入为两行,第一行为参数K,第二行为字符串S。

输出描述:

输出转换后的字符串。

示例1

输入

3

12abc-abCABc-4aB@

输出

12abc-abc-ABC-4aB-@
 

    public static String strChange(String str, Integer k) {
        String[] arr = str.split("-");
        StringBuffer newStr = new StringBuffer();
        newStr.append(arr[0]);
        StringBuffer childs = new StringBuffer();
        for (int i = 1; i < arr.length; i++) {
            childs.append(arr[i]);
        }
        //双指针
        int left = 0;
        int right = left + k;
        while (right < childs.length()) {
            String substring = childs.substring(left, right);
            String s = countUpCase(substring.toString(), k);
            newStr.append("-").append(s);
            left += k;
            right = left + k;
        }
        if (left < childs.length()) {
            newStr.append("-").append(childs.substring(left));
        }
        return newStr.toString();
    }

    public static String countUpCase(String str, int k) {
        int letter = 0;
        int capital = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
                letter++;
            }
            if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
                capital++;
            }
        }
        if (capital == letter) {
            return str;
        } else if (letter > k / 2) {
            return str.toLowerCase();
        } else {
            return str.toUpperCase();
        }
    }

5、组成最大数

小组中每位都有一张卡片,卡片上是6位内的正整数,将卡片连起来可以组成多种数字,计算组成的最大数字。

输入描述:

“,”号分割的多个正整数字符串,不需要考虑非数字异常情况,小组最多25个人

输出描述:

最大的数字字符串

输入

4589,101,41425,9999

输出

9999458941425101

    public static String maxStr(String str) {
        String[] arr = str.split(",");
        //使用大顶堆 重写字符串比较方法
        PriorityQueue<String> queue = new PriorityQueue<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int len1 = o1.length();
                int len2 = o2.length();
                int lim = Math.min(len1, len2);
                char v1[] = o1.toCharArray();
                char v2[] = o2.toCharArray();

                int k = 0;
                while (k < lim) {
                    char c1 = v1[k];
                    char c2 = v2[k];
                    if (c1 != c2) {
                        return c2 - c1;
                    }
                    k++;
                }
                return len1 - len2;
            }
        });
        for (int i = 0; i < arr.length; i++) {
            queue.offer(arr[i]);
        }
        StringBuffer sb = new StringBuffer();
        while (!queue.isEmpty()) {
            sb.append(queue.poll());
        }
        return sb.toString();
    }

6、高矮个子排队

现在有一队小朋友,他们高矮不同,我们以正整数数组表示这一队小朋友的身高,如数组{5,3,1,2,3}。

我们现在希望小朋友排队,以“高”“矮”“高”“矮”顺序排列,每一个“高”位置的小朋友要比相邻的位置高或者相等;每一个“矮”位置的小朋友要比相邻的位置矮或者相等;

要求小朋友们移动的距离和最小,第一个从“高”位开始排,输出最小移动距离即可。

例如,在示范小队{5,3,1,2,3}中,{5, 1, 3, 2, 3}是排序结果。{5, 2, 3, 1, 3} 虽然也满足“高”“矮”“高”“矮”顺序排列,但小朋友们的移动距离大,所以不是最优结果。

移动距离的定义如下所示:

第二位小朋友移到第三位小朋友后面,移动距离为1,若移动到第四位小朋友后面,移动距离为2;
 

    public static int[] queueUp(int[] arr) {
       // {5,3,1,2,3}
        //5,1,3,2,3

        //4 1 3 5 2
        //4,1,5,3,2
        //4,1,5,2,3

        //使用双指针,当前指向和下一个进行比较,如果是偶数下标就判断是否大,奇数判断是否小
        int cur = 0;
        int next = cur+1;
        while(next != arr.length){
            if(cur % 2 == 0){
                if(arr[cur] < arr[next]) swap(arr,cur,next);
            }else{
                if(arr[cur] > arr[next]) swap(arr,cur,next);
            }
            cur++;
            next++;
        }
        return arr;
    }
    
    public static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

7、猴子爬山

一天一只顽猴想去从山脚爬到山顶,途中经过一个有个N个台阶的阶梯,但是这猴子有一个习惯: 每一次只能跳1步或跳3步,试问猴子通过这个阶梯有多少种不同的跳跃方式?

//动态规划    
public static int monkey(int n){
        //dp[n] = dp[n-1]+dp[n-3]
        int[] dp = new int[n+1];
        //确定边界
        dp[0] = 1;dp[1]= 1;
        dp[2] = 1;dp[3] = 2;
        for(int i = 4 ; i < n+1;i++){
            dp[i] = (dp[i-3]+dp[i-1])%1000000007;
        }
        return dp[n];
    }

8、分糖果

小明从糖果盒中随意抓一把糖果,每次小明会取出一半的糖果分给同学们。

当糖果不能平均分配时,小明可以选择从糖果盒中(假设盒中糖果足够)取出一个糖果或放回一个糖果。

小明最少需要多少次(取出、放回和平均分配均记一次),能将手中糖果分至只剩一颗

输入描述:

抓取的糖果数(<10000000000):

15

输出描述:

最少分至一颗糖果的次数:

5
 

    public static int candy(int n){
        int count = 0;

        //2 count = 1 2/2 = 1 count =2
        for(int i = n ; i != 1 ; i /= 2, count++){
            if(n == 3){
                return count += 2;
            }
            if(i % 2 != 0){
                if ((i + 1) / 2 % 2 == 0) i++;
                else i--;
                count++;
            }
        }
        return count;
    }

9、报数游戏

100个人围成一圈,每个人有一个编码,编号从1开始到100。他们从1开始依次报数,报到为M的人自动退出圈圈,然后下一个人接着从1开始报数,直到剩余的人数小于M。请问最后剩余的人在原先的编号为多少?

//约瑟夫问题,单循环链表(取余完成)   
 public static void Josef(int m){
        List<Integer> list = new LinkedList<>();
        int person = 100;
        for (int i = 1; i <= person; i++) {
            list.add(i);
        }
        int index = 0;
        //3
        //index = 2 % 100 = 2
        //index = 4 % 99 = 4
        while (list.size() >= m) {
            index = (index + m - 1) % list.size();
            list.remove(index);
        }
        System.out.println(list);
    }

10、消消乐游戏

消消乐游戏

游戏规则:输入一个只包含英文字母的字符串,字符串中的两个字母如果相邻且相同,就可以消除。

在字符串上反复执行消除的动作,直到无法继续消除为止,此时游戏结束。

输出最终得到的字符串长度。

    public static int clear(String str){
        //stringbuffer做栈
        StringBuffer stack = new StringBuffer();
        int head = -1;
        for(int i = 0 ; i < str.length(); i++){
            if(stack.length() > 0){
                if (stack.charAt(head) == str.charAt(i)){
                    stack.deleteCharAt(head);
                    head--;
                    continue;
                }
            }
            stack.append(str.charAt(i));
            head++;
        }
        return stack.length();
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值