牛客网十道题目1

原题目地址: 牛客10道练习题1

发现有问题, 请提出来. 谢谢啦!

class Exam1 {
	/**
     * 1、求解连续数列
     * <p>
     * 已知连续正整数数列{K}=K1,K2,K3...Ki的各个数相加之和为S,i=N (0<S<100000, 0<N<100000), 求此数列K。
     * 对连续理解错了, 这里的连续是限制d=1. 所以才会出现下面这代码, 这代码原本的意思是解所有的和等于Sn的前N项. 包含d=1的. 
     * @param s
     */
     public static void t1(String s) {
        int[] split = Arrays.stream(s.split("\\s+")).mapToInt(Integer::parseInt).toArray();
        // 数列和
        int Sn = split[0];
        // 项数目
        int n = split[1];
        if (!Utils.isBetweenAnd(Sn, 0, 100000) || !Utils.isBetweenAnd(n, 0, 100000)) {
            System.out.println("-1");
            return;
        }
        // 公差d, 默认从0开始
        Double d = 0.0;
        // a1的最大值
        Double a1 = getA1(d, Sn, n);
        if (a1.intValue() != a1) {
            a1 = Math.floor(a1);
            d = getD(a1, Sn, n);
        }
        boolean flag = false;

        while (a1 > 0) {
            if (d.intValue() == d && d == 1) {
//                    System.out.println("a1: " + a1.intValue() + "\td:" + d.intValue());
//                    d = getD(--a1, Sn, n);
//                    continue;
                flag = true;
                break;
            } else {
                a1--;
            }
            d = getD(a1, Sn, n);
        }
        if (!flag) {
            System.out.println("-1");
            return;
        }
        String result = "";
        for (int i = 0; i < n; i++) {
            result += (int) (a1 + i * d) + " ";
        }
        System.out.println(result);
    }

    /**
     * 根据公差d 求首项
     *
     * @param d 公差
     * @return 首项
     */
    private static double getA1(double d, double Sn, double n) {
        return Sn / n - (n - 1) * d / 2;
    }

    /**
     * 根据首项求公差d
     *
     * @param a1 首项
     * @return 首项
     */
    private static double getD(double a1, double Sn, double n) {
        return 2 * (Sn / n - a1) / (n - 1);
    }

    /**
     * 2、查找众数及中位数
     * <p>
     * 众数是指一组数据中出现次数量多的那个数,众数可以是多个
     * <p>
     * 中位数是指把一组数据从小到大排列,最中间的那个数,如果这组数据的个数是奇数,那最中间那个就是中位数,如果这组数据的个数为偶数,那就把中间的两个数之和除以2,所得的结果就是中位数
     * <p>
     * 查找整型数组中元素的众数并组成一个新的数组,求新数组的中位数
     * 输入描述:
     * <p>
     * 输入一个一维整型数组,数组大小取值范围 0<N<1000,数组中每个元素取值范围 0<E<1000
     * <p>
     * 输出描述:
     * <p>
     * 输出众数组成的新数组的中位数
     *
     * @param s
     */
    public static void t2(String s) {
         List<Integer> nums = Arrays.stream(s.split("\\s+")).map(Integer::parseInt).collect(Collectors.toList());
        int len = nums.size();
        if (len == 0 || len > 1000) {
            System.err.println("invalid input");
            return;
        }
        Collections.sort(nums);

        if (nums.get(len - 1) > 1000 || nums.get(len - 1) <= 0) {
            System.err.println("invalid input");
            return;
        }

        // 分组
        Map<Integer, Long> collect = nums.stream().collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()));

        // 找到数目最大的值
        int max = Math.toIntExact(collect.values().stream().max(Long::compareTo).get());

        // 求众数数组
        List<Integer> mode = new ArrayList<>();
        collect.forEach((key, value) -> {
            if (value == max) {
                mode.add(key);
            }
        });
        // 众数数组排序
        Collections.sort(mode);
        // 求中位数
        if (mode.size() % 2 == 1) {
            System.out.println(mode.get((mode.size() + 1) >> 2));
        } else {
            Double value = (mode.get(mode.size() >> 2) + mode.get(mode.size() >> 2 - 1)) / 2.0;
            if (value.intValue() == value) {
                System.out.println(value.intValue());
            } else {
                System.out.println(value);
            }
        }
    }

    /**
     * 3、寻找相同子串
     * <p>
     * 给你两个字符串 t 和 p ,要求从 t 中找到一个和 p 相同的连续子串,并输出该字串第一个字符的下标。
     *
     * @param t
     * @param p
     */
    public static void t3(@NotNull String t, @NotNull String p) {
//        Scanner scanner = new Scanner(System.in);

//        String t = scanner.nextLine();
//        String p = scanner.nextLine();

        if (t.length() < p.length() || t.length() > 1000000 || p.length() > 10000) {
            System.err.println("invalid input");
            return;
        }

        if ("".equals(t) || "".equals(p)) {
            System.out.println("No");
            return;
        }

        int i = t.indexOf(p);
        if (i > -1) {
            System.out.println(i + 1);
        } else {
            System.out.println("No");
        }
    }

    /**
     * 4、字符串统计
     * <p>
     * 给定两个字符集合,一个为全量字符集,一个为已占用字符集。已占用的字符集中的字符不能再使用,要求输出剩余可用字符集。
     * <p>
     * <p>
     * <p>
     * 输入描述:
     * <p>
     * 1、输入为一个字符串,一定包含@符号。@前的为全量字符集,@后的字为已占用字符集。
     * <p>
     * 2、已占用字符集中的字符一定是全量字符集中的字符。字符集中的字符跟字符之间使用英文逗号分隔。
     * <p>
     * 3、每个字符都表示为字符加数字的形式,用英文冒号分隔,比如a:1,表示1个a字符。
     * <p>
     * 4、字符只考虑英文字母,区分大小写,数字只考虑正整形,数量不超过100。
     * <p>
     * 5、如果一个字符都没被占用,@标识仍然存在,例如a:3,b:5,c:2@
     * <p>
     * 输出描述:
     * <p>
     * 输出可用字符集,不同的输出字符集之间回车换行。
     * <p>
     * 注意,输出的字符顺序要跟输入一致。不能输出b:3,a:2,c:2
     * <p>
     * 如果某个字符已全被占用,不需要再输出。
     */
    public static void t4(@NotNull String s) {
        // Scanner scanner= new Scanner(System.in);
        // String s = scanner.nextLine();
        if (s.length() == 0) {
            System.err.println("invalid input");
            return;
        }
        String[] split = s.split("@");
        if (split.length != 2) {
            System.err.println("invalid input");
            return;
        }
        String[] tempArray;
        // all
        LinkedMap<String, Integer> all = new LinkedMap<>();
        tempArray = split[0].split(",");
        for (int i = 0; i < tempArray.length; i++) {
            String[] map = tempArray[i].split(":");
            all.put(map[0], Integer.parseInt(map[1]));
        }
        // used
        LinkedMap<String, Integer> used = new LinkedMap<>();
        tempArray = split[1].split(",");
        for (int i = 0; i < tempArray.length; i++) {
            String[] map = tempArray[i].split(":");
            used.put(map[0], Integer.parseInt(map[1]));
        }

        used.forEach((k, v) -> {
            int V = all.get(k) - v;
            if (V > 0) {
                all.put(k, all.get(k) - v);
            } else {
                all.remove(k);
            }

        });
        StringBuilder sb = new StringBuilder();
        all.forEach((k, v) -> {
            sb.append(k).append(":").append(v).append(",");
        });
        System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
    }

    /**
     * 5、磁盘容量排序
     * <p>
     * 磁盘的容量单位常用的有M,G,T这三个等级,它们之间的换算关系为1T = 1024G,1G = 1024M,现在给定n块磁盘的容量,请对它们按从小到大的顺序进行稳定排序,例如给定5块盘的容量,1T,20M,3G,10G6T,3M12G9M排序后的结果为20M,3G,3M12G9M,1T,10G6T。注意单位可以重复出现,上述3M12G9M表示的容量即为3M+12G+9M,和12M12G相等。
     * <p>
     * <p>
     * <p>
     * 输入描述:
     * <p>
     * 输入第一行包含一个整数n(2 <= n <= 100),表示磁盘的个数,接下的n行,每行一个字符串(长度大于2,小于30),表示磁盘的容量,由一个或多个格式为mv的子串组成,其中m表示容量大小,v表示容量单位,例如20M,1T,30G,10G6T,3M12G9M。
     * <p>
     * <p>
     * <p>
     * 磁盘容量m的范围为1到1024的正整数,容量单位v的范围只包含题目中提到的M,G,T三种,换算关系如题目描述。
     * <p>
     * 输出描述:
     * <p>
     * 输出n行,表示n块磁盘容量排序后的结果。
     **/
    public static void t5() {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        if (n > 100 || n < 2) {
            System.err.println("invalid input");
            return;
        }
        String[] disks = new String[n];
        // 对应位置的磁盘容量
        int[] diskCapacity = new int[n];
        String diskStrTemp;
        for (int i = 0; i < n; i++) {
            diskStrTemp = scanner.next();
            if (diskStrTemp.length() < 2 || diskStrTemp.length() > 30) {
                System.err.println("invalid input");
                return;
            }

            disks[i] = diskStrTemp;
            diskCapacity[i] = Utils.conversionDiskCapacityToM(diskStrTemp);
        }

        int diskCapacityTemp = 0;
        // 插入排序
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j > 0; j--) {
                // 小于的时候才交换, 否则直接break掉该次循环
                if (diskCapacity[i] > diskCapacity[j]) {
                    diskCapacityTemp = diskCapacity[i];
                    diskCapacity[i] = diskCapacity[j];
                    diskCapacity[j] = diskCapacityTemp;

                    diskStrTemp = disks[i];
                    disks[i] = disks[j];
                    disks[j] = diskStrTemp;
                } else {
                    break;
                }
            }
        }

        Arrays.stream(disks).forEach(System.out::println);
    }

    /**
     * 6、太阳能板最大面积
     * <p>
     * 给航天器一侧加装长方形或正方形的太阳能板(图中的红色斜线区域),需要先安装两个支柱(图中的黑色竖条),再在支柱的中间部分固定太阳能板。但航天器不同位置的支柱长度不同,太阳能板的安装面积受限于最短一侧的那根支柱长度。如图:
     * <p>
     * 现提供一组整形数组的支柱高度数据,假设每根支柱间距离相等为1个单位长度,计算如何选择两根支柱可以使太阳能板的面积最大。
     * <p>
     * <p>
     * <p>
     * 输入描述:
     * <p>
     * 10,9,8,7,6,5,4,3,2,1
     * <p>
     * 注:支柱至少有2根,最多10000根,能支持的高度范围1~10^9的整数。柱子的高度是无序的,例子中递减只是巧合。
     *
     * @param s
     */
    public static void t6(@NotNull String s) {
        // 柱子
        int[] pillars = Arrays.stream(s.split(",")).mapToInt(Integer::parseInt).toArray();
        // 柱子间的容量数组长度
        int len = pillars.length - 1;
        // 柱子间的容量数组
        int[] pillarsLoad = new int[len];

        // 填充容量数组
        for (int i = 0; i < len; i++) {
            pillarsLoad[i] = Math.min(pillars[i], pillars[i + 1]);
        }

        int max = 0, temp, minPillarsLoad = pillarsLoad[0];

        // 第一个容量的位置
        for (int i = 0; i < len - 1; i++) {
            // 默认第一个是最小容量
            minPillarsLoad = pillarsLoad[i];
            // 末尾容量的位置, 从第一个柱子旁边移动到最后.
            for (int j = i + 1; j < len; j++) {
                // 求最小容量
                minPillarsLoad = Math.min(minPillarsLoad, pillarsLoad[j]);
                // 求当前的max
                temp = minPillarsLoad * (j - i + 1);
                max = Math.max(temp, max);
            }
        }

        // out
        System.out.println(max);
	}
    /**
     * 7、靠谱的车
     * <p>
     * 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。
     * <p>
     * <p>
     * <p>
     * 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。
     * <p>
     * <p>
     * <p>
     * 比如:
     * <p>
     * 1.     23再多一块钱就变为25;
     * <p>
     * 2.     39再多一块钱变为50;
     * <p>
     * 3.     399再多一块钱变为500;
     * <p>
     * 小明识破了司机的伎俩,准备利用自己的学识打败司机的阴谋。
     * <p>
     * 给出计费表的表面读数,返回实际产生的费用。
     * <p>
     * 思路 -> 每九个数进1, 那么把对应的数字转成九进制数字, 在计算其对应的十进制即可; 可以参考numberMap映射
     */
    /**
     * @param n 伪九进制
     */
    public static void t7(int n) {

        if (n < 1 || n > 888888888) {
            System.err.println("invalid input");
            return;
        }
//        Map<Character, Integer> numberMap = new HashMap<Character, Integer>() {{
//            put('0', 0);
//            put('1', 1);
//            put('2', 2);
//            put('3', 3);
//            put('5', 4);
//            put('6', 5);
//            put('7', 6);
//            put('8', 7);
//            put('9', 8);
//        }};

        String N = n + "";
        int result = 0, m = 1;
        char temp;
        for (int i = N.length() - 1; i >= 0; i--) {
            temp = N.charAt(i);
            if (temp < '4') {
                result += (temp - 48) * m;
            } else
                result += (temp - 49) * m;
            m *= 9;
        }
        System.out.println(result);
    }

    /**
     * 8、整数对最小和
     * <p>
     * 给定两个整数数组array1、array2,数组元素按升序排列。假设从array1、array2中分别取出一个元素可构成一对元素,现在需要取出k对元素,并对取出的所有元素求和,计算和的最小值
     * <p>
     * 注意:两对元素如果对应于array1、array2中的两个下标均相同,则视为同一对元素。
     */
    public static void t8(int[] arr1, int[] arr2, int k) {
		
        int len1 = arr1.length;
        int len2 = arr2.length;
        if (k > len1 * len2) {
            System.err.println("error");
            return;
        }

        int result = 0;

        int[] sums = new int[arr1.length * arr2.length];

        for (int i = 0; i < arr1.length; i++) {
            for (int j = 0; j < arr2.length; j++) {
                sums[j + i * arr2.length] = arr1[i] + arr2[j];
            }
        }
        Arrays.sort(sums);
        while (k > 0) {
            result += sums[--k];
        }
        /**
         * i:0    1     1   0
         * + 2    2     3   3
         * j:0    0     1   1
         */
        System.out.println(result);

    }

    /**
     * 9、判断字符串子序列
     * <p>
     * 给定字符串 target和 source, 判断 target 是否为 source 的子序列。
     * <p>
     * 你可以认为 target 和  source 中仅包含英文小写字母。字符串 source可能会很长(长度 ~= 500,000),而 target 是个短字符串(长度 <=100)。
     * <p>
     * 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"abc"是"aebycd"的一个子序列,而"ayb"不是)。
     *
     * @param target 短字符串
     * @param source 长字符串
     */
    public static void t9(String target, String source) {
        int len1 = target.length();
        int len2 = source.length();
        if (len1 > 100 || len2 > 500000) {
            System.err.println("error");
            return;
        }
        int i = len1 - 1;
        int j = len2 - 1;
        I:
        for (; i >= 0; i--) {
            for (; j >= 0; j--) {
                if (target.charAt(i) == source.charAt(j)) {
                    if (i == 0)
                        break I;
                    j--;
                    break;
                }
            }
        }
        System.out.println(j);
    }

    /**
     * 10、按身高和体重排队
     * <p>
     * 某学校举行运动会,学生们按编号(1、2、3…n)进行标识,现需要按照身高由低到高排列,对身高相同的人,按体重由轻到重排列;对于身高体重都相同的人,维持原有的编号顺序关系。请输出排列后的学生编号。
     * <p>
     * <p>
     * <p>
     * 输入描述:
     * <p>
     * 两个序列,每个序列由n个正整数组成(0 < n <= 100)。第一个序列中的数值代表身高,第二个序列中的数值代表体重。
     * <p>
     * 输出描述:
     * <p>
     * 排列结果,每个数值都是原始序列中的学生编号,编号从1开始
     *
     * @param n       几个人
     * @param heights 身高数组
     * @param wrights 体重数组
     */
    public static void t10() {
        Scanner sc = new Scanner(System.in);

        int len = sc.nextInt();
        while (sc.hasNextInt()) {
            int[] heights = new int[len];
            int[] weights = new int[len];
            for (int i = 0; i < len; i++) {
                heights[i] = sc.nextInt();
            }
            for (int i = 0; i < len; i++) {
                weights[i] = sc.nextInt();
            }
            int[] code = new int[len];
            for (int i = 0; i < len; i++) {
                code[i] = i + 1;
            }
            int temp;
            // 身高: 低到高
            // 体重: 轻到重
            for (int i = 1; i < len; i++) {
                temp = heights[i];
                for (int j = i; j > 0; j--) {
                    if (heights[j - 1] > heights[j]) {
                        swap(heights, j, j - 1);
                        swap(weights, j, j - 1);
                        swap(code, j, j - 1);
                    } else if (heights[j - 1] == heights[j]) {
                        // 身高相等, 比较体重
                        if (weights[j - 1] > weights[j]) {
                            swap(weights, j, j - 1);
                            swap(code, j, j - 1);
                        }
                    }
                }
            }

            for (int i = 0; i < len; i++) {
                System.out.print(heights[i] + " " + code[i] + " ");
            }
            break;
         }
     }

Utils.java

class Utils{
	 /**
     * @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;
    }
    
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
	 /**
     * 将容量数据实体化, 转换为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


//        Exam1.t1("525 6");

        Exam1.t2("10 11 21 19 21 17 21 16 21 18 15");
        Exam1.t2("2 1 5 4 3 3 9 2 7 4 6 2 15 4 2 4");
        Exam1.t2("5 1 5 3 5 2 5 5 7 6 7 3 7 11 7 55 7 9 98 9 17 9 15 9 9 1 39 ");
        Exam1.t2("1 8 0 7 7 7 7 6 6 6 6 1 1 1 5 5 5 5");

//        Exam1.t3("AVERDXIVYERDIAN", "AN ");
//        Exam1.t4("a:3,b:5,c:2@a:1,b:2");
//        Exam1.t5();

//        Exam1.t6("10,1,8,7,6,5,5,5,5,5");

//        Exam1.t7(5);
//        Exam1.t7(888888888);

//        Exam1.t8(new int[]{1, 1, 2}, new int[]{1, 2, 3},6);
//        Exam1.t9("ccc", "abcccc");

//        Exam1.t10();

不想输入, 有的地方就没用Scanner. 如果发现有问题, 请及时跟我说
(第八题复杂度高了,我有空优化。)


大家互相进步啊~
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值