滴滴笔试 09.17 已更正第一题

第一题

正整数,没有前导0
可以被3整除
?是需要猜测的位置,相邻的数字不能相同
输出可能的最小数。
一定存在一个 ?

输入:?12?0?9??
输出:212101902

之前 81%的代码的问题在于,数组赋值的时候,需要初始化为 -1,而不是默认的 0,否则,如果两个 "?" 相连 & 没有较好处理,第一个 "?" 会以为后面存在 0 而不能选择 0.

补充,这个题可以用贪心的方法来解决,只需要考虑下最后一个问号的处理就好了。不需要DFS。

    static boolean find;
    static int n;
    static int[] ret; // 记录最终结果
    public static void main4(String s) {
        n = s.length();
        int cnt = 0;
        find = false;
        int arr[] = new int[n];
        ret = new int[n];
        Arrays.fill(arr, -1); // 出错的原因


        List<Integer> l = new ArrayList<>();
        for(int i = 0; i < n; i++){
            if(Character.isDigit(s.charAt(i))){
                cnt += s.charAt(i) - '0'; // 记录和
                arr[i] = s.charAt(i) - '0';  // 记录值
            }else{
                l.add(i); // 记录 ? 位置
            }
        }
        if(n == 1){ // 长度1,且一定有?,直接返回3
            System.out.println(3);
            return ;
        }
        dfs(arr, 0, l, cnt%3);
        StringBuilder sb = new StringBuilder();
        for(int i: ret){
            sb.append(i);
        }
        System.out.println(sb.toString());
    }

    public static void dfs(int arr[], int idx, List<Integer> list, int sumv) {
        if(find) return; // 已经找到,直接返回
        if(idx == list.size()){  // 已经查看完所有的?,进行处理
            if(sumv % 3 == 0){ 
                find = true;
                for(int i  = 0; i < arr.length; i++) ret[i] = arr[i];
            }
            return;
        }
        int arrIdx = list.get(idx); // 当前的 ?
        for(int i = 0; i < 10; i++){
            if(arrIdx == 0){
                if(i == 0) continue; // 如果 ?在开头 & i = 0
            }else if(arr[arrIdx-1] == i) continue;

            if(arrIdx != n-1 && arr[arrIdx+1] == i) continue;
            arr[arrIdx] = i;
            dfs(arr, idx+1, list, sumv + i);
        }
    }

贪心,参考思路吧,没有验证。

    public static String TanXin(String s) {
        n = s.length();
        if (n == 1) return "3";
        int cnt = 0;
        int arr[] = new int[n];
        Arrays.fill(arr, -1);
        int numOfWenHao = 0;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) != '?') {
                cnt += s.charAt(i) - '0';
                arr[i] = s.charAt(i) - '0';
            }else{
                numOfWenHao++;
            }
        }

        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '?') {
                Set<Integer> set = new HashSet<>(3); // 不能使用的值
                if(i == 0) set.add(0); // 头部
                if(i != 0) set.add(arr[i-1]); // 后部
                if(i != n-1) set.add(arr[i+1]); // 前部
                for(int j = 0; j < 10; j++){
                    // 1. 剩余 ? 个数 > 1,直接取可行的数中最小的
                    // 2. 剩余 ? 个数 = 1,还需要满足全部模3为0.
                    if((numOfWenHao != 1 && !set.contains(j)) ||
                        (numOfWenHao == 1 && !set.contains(j) && (j + cnt) % 3 == 0)){
                            arr[i] = j;
                            cnt += j;
                            numOfWenHao--;
                            break;
                    }
                }
            }
        }
        StringBuilder sb = new StringBuilder();
        for (int i : arr) {
            sb.append(i);
        }
        return sb.toString();
    }

第二题

题目:
栅栏被按顺序编号为1到1000000000。每个栅栏要刷 p 次 A 油漆和 q 次 B 油漆。

第一行有三个正整数n,p,q(1<=n<=100000,1<=p,q<=n),代表刷漆的次数,以及两个参数 p 和 q。

第二到四行给出了一个大小为3*n的矩阵,第 i 列的三个数从上到下记为l,r,t(1<=l,r<=1000000000,1<=t<=2),代表第i次刷漆将编号在 l 到 r 之间的栅栏刷了一遍 t号油漆。

问,最后有多少个栅栏满足条件。

输入:
5 2 2
1 1 2 3 2
3 5 4 5 4
1 2 1 1 2

输出:
3

方法:
差分数组+离散化

   public static void main2(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int p = sc.nextInt(), q = sc.nextInt();
        int arr[][] = new int[n][3];
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < n; j++){
                arr[j][i] = sc.nextInt();
            }
        }
        Map<Integer, Integer> m1 = new HashMap<>();
        Map<Integer, Integer> m2 = new HashMap<>();
        for(int i = 0; i < n; i++){
            if(arr[i][2] == 1){
                m1.put(arr[i][0], m1.getOrDefault(arr[i][0], 0) + 1);
                m1.put(arr[i][1]+1, m1.getOrDefault(arr[i][1]+1, 0) - 1);
            }else{
                m2.put(arr[i][0], m2.getOrDefault(arr[i][0], 0) + 1);
                m2.put(arr[i][1]+1, m2.getOrDefault(arr[i][1]+1, 0) - 1);
            }
        }

        List<int[]> l1 = getOk(m1, p); // 获取满足条件的 A 燃料所处的区间
        List<int[]> l2 = getOk(m2, q); // 获取满足条件的 B 燃料所处的区间
        System.out.println(func(l1, l2)); // 两个区间重叠部分
    }


    public static int func(List<int[]> l1, List<int[]> l2){
        // 查看两个区间重叠的个数
        int i = 0, j = 0;
        int a = l1.size(), b = l2.size();
        int cnt = 0;
        while(i < a && j < b){
            int arr1[] = l1.get(i);
            int arr2[] = l2.get(j);
            cnt += Math.max(Math.min(arr1[1], arr2[1]) - Math.max(arr1[0], arr2[0]) + 1, 0);
            if(arr1[1] >= arr2[1]){
                j++;
            }else{
                i++;
            }
        }
        return cnt;
    }

    public static List<int[]> getOk(Map<Integer, Integer> map, int p){
        List<Integer> keys = new ArrayList<>(map.keySet());
        List<int[]> ret = new ArrayList<>();
        if(keys.isEmpty()) return ret;

        keys.sort((a, b) -> a - b);

        int pre = keys.get(0); // 可行区间的左侧索引
        int cnt = map.get(pre); // 粉刷数目
        int len = 0; // 可行区间的长度
        for(int i = 1; i < keys.size(); i++){
            int idx = keys.get(i);
            if(cnt >= p){ // 之前的区间达到 p 值,更新长度
                len = idx - pre;
            }else{ // [idx-1] 位置没有达到 p 值
                if(len > 0){ // 保存区间
                    ret.add(new int[]{pre, pre + len-1});
                }
                pre = idx; // 更新起始点
                len = 0;  // 更新长度
            }
            cnt += map.get(idx); // 更新当前点的粉刷数
        }
        if(len > 0){  // p == 1 时需要多个判断
            ret.add(new int[]{pre, pre + len-1});
        }

        return ret;
    }
#滴滴##笔试##23届秋招笔面经#
全部评论
偷哥,我写出来了不过不是dfs,直接遍历
点赞 回复 分享
发布于 2022-09-17 18:48 山西
Hello,我是恒生电子股份有限公司的校园大使,不想简历投递后“泡池子”, 登录链接:campus.hundsun.com/campus/jobs 填写我的推荐码:EVKGKJ 投递,简历第一时间送到HR面前,可查进度,快来投递吧~
点赞 回复 分享
发布于 2022-09-17 22:38 江西

相关推荐

12-17 19:24
门头沟学院 Java
黑皮白袜臭脚体育生:看你后备隐藏能源多不多,最坏的情况就是每个星期的三天课程都不在周末,那么每个星期公司那边请一天半假,半天假请上午,上午正常上课,早点溜去请病假或者中午去请病假,然后坐高铁回公司,记得提前请学校那边实训课下午的病假,就说肚子痛,然后下午就公司上班,第二个实训周同样,但病假理由是牙齿痛,像肚子痛和牙齿痛这种校医院不方便查,会同意你出去检查的,很多时候都不需要你的检查报告,这里的问题就是最坏情况时距离过远的话可能要坐飞机才能赶上,然后请假的话不一定请了就有回应,可能要等老师,然后距离不远不近的情况到公司了也是迟到,得想个说辞掩盖一下,顺便晚上多加点班补下时间,特殊情况特殊处理,正常不建议加班常态化,这样每个星期可以多凑出来半天,老师面子也有了公司那边也不至于无法交差,就是有点费存粮,如果哪个星期的三天课有一天或两天在周末的话那就更好应对了。实习还是建议去,学校的课懂的都懂
点赞 评论 收藏
分享
评论
5
7
分享
牛客网
牛客企业服务