算法笔记day1

饿了么2023年0817面试题

第一题

总体思路:先找出用了哪些字符,然后遍历字符串不同的就修改,重要的点是为了每个字符都被用到,需要++操作。

public class 小红的字符串构造 {
//小红拿到了一个字符串
//s,她准备构造一个和s长度相同的字符串
//t:满足以下条件:
//1.t的字符集和s的相同(去重后的,也就是说不考虑数量)
//2.t的每个位置的字符都和s不同。
//例如若 s="aabbc",那么t可以构造为"cbaca"。你能帮帮小红吗?
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        Set<Character> charSet = new HashSet<>();
        for (char c : s.toCharArray()) {
            charSet.add(c);
        }
        if (charSet.size() == 1) {
            System.out.println(-1);
            return;
        }
        // 将字符集合转换为字符数组,并排序
        Character[] uniqueChars = charSet.toArray(new Character[0]);
        Arrays.sort(uniqueChars);
        // 构造字符串 t
        StringBuilder t = new StringBuilder();
        int idx = 0;
        //为了出现所有字符,用一个就下一个
        for (char c : s.toCharArray()) {
            if (c == uniqueChars[idx]) {
                t.append(uniqueChars[(idx + 1) % uniqueChars.length]);
            } else {
                t.append(uniqueChars[idx]);
            }
            idx = (idx + 1) % uniqueChars.length;
        }
        System.out.println(t.toString());
    }
}

第二题

能想到用送出时间做基准进行判断,第二天怎么处理之类的

* 小红在饿了么上面点了一个外卖,饥肠辘辘的她等骑手等得望眼欲穿。
 * 已知小红在时刻t1点了外卖,饿了么上面显示预计送达时间为 t2,实际送达时间为t3 。请你判断外卖是否超时?
 */

public class 小红等外卖 {
    //    第一行输入一个正整数t,代表询问次数。
//接下来的3*t行,每 3 行代表一次询问:
//第一行为点外卖的时刻t_1,第二行为预计送达时间t_2,第三行为实际送达时间t_3。
//保证骑手送外卖的预期花费时间和实际花费时间均不超过 2 小时。
    //难点在于找到基准点分类讨论,time1可以作为基准点,正数距离越小越近,负数绝对值越大越远,通过这个进行讨论
    public static boolean isFoodDelayed(String t1, String t2, String t3) {
        // 将时间字符串转换为分钟表示
        int hour1 = Integer.parseInt(t1.substring(0, 2));
        int min1 = Integer.parseInt(t1.substring(3));
        int time1 = hour1 * 60 + min1;
        int hour2 = Integer.parseInt(t2.substring(0, 2));
        int min2 = Integer.parseInt(t2.substring(3));
        int time2 = hour2 * 60 + min2;
        int hour3 = Integer.parseInt(t3.substring(0, 2));
        int min3 = Integer.parseInt(t3.substring(3));
        int time3 = hour3 * 60 + min3;
        if (time3-time1<0&&time2-time1<0){
            return Math.abs(time3-time1) < Math.abs(time2-time1) ;
        }else if (time3-time1<0&&time2-time1>0){
            return true;
        } else  if (time3-time1>0&&time2-time1<0){
            return false;
        }else return time3>time2;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt(); // 询问次数
        scanner.nextLine(); // 消耗换行符

        for (int i = 0; i < t; i++) {
            String t1 = scanner.nextLine(); // 点外卖的时间
            String t2 = scanner.nextLine(); // 预计送达时间
            String t3 = scanner.nextLine(); // 实际送达时间

            boolean isDelayed = isFoodDelayed(t1, t2, t3);
            if (isDelayed) {
                System.out.println("Yes");
            } else {
                System.out.println("No");
            }
        }
    }
}

第三题

主要就是图求距离。

 * 小红在第三新北林市的学园城送外卖,学园城中有非常多的学校,学园城里有一个美食街。
 * 小红每次会接一些同一个学校的订单,然后从美食街取餐出发,再骑车将外卖送到学校,最后回到美食街,
 * 以此往复学园城有 n 个结点, m 条道路,美食街为1号结点,剩下的结点都是学校,保证学园城中所有结点连通。
 * 给出小红每次要送外卖的学校,请计算小红最少需要骑行的距离。
 */

public class 小红送外卖 {
    static int[] curSide ;
    static int[] former;
    static int[] to;
    static int[] weight;
    static int cnn;
    //思路,迪克斯拉算法,求得从某个点到所有地方的距离之和
    //可以用前向星+迪克斯拉算法
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 结点数
        int m = scanner.nextInt(); // 边数
        int q = scanner.nextInt(); // 送外卖次数

         curSide = new int[n+1];
         //无向图
         former=new int[2*m+1];
         to=new int[2*m+1];
         weight=new int[2*m+1];
         cnn=0;
        for (int i = 0; i < m; i++) {
            //建前向星图
            int from = scanner.nextInt();
            int arrive=scanner.nextInt();
            int w=scanner.nextInt();
            add(from,arrive,w);
            add(arrive,from,w);
        }
        //此时迪克斯拉算法
        long[] distance=new long[n+1];
        Arrays.fill(distance,Integer.MAX_VALUE);
        int[] visited=new int[n+1];
        long sum=0;
        PriorityQueue<int[]> heap = new PriorityQueue<>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1]-o2[1];
            }
        });
        int cur=0;
        heap.add(new int[]{1,0});
        while (!heap.isEmpty()&&cur<n) {
            int[] poll = heap.poll();
            int pos = poll[0];
            int dis = poll[1];
            if (visited[pos] == 1) {
                //看过就不管了
                continue;
            }
            //没看过
            //标记为看过,写距离
            visited[pos] = 1;
            distance[pos] = dis;
            //将当前这个点的所有边放进堆里面去
            int curS = curSide[pos];
            while (curS != 0) {
                //这条边去哪
                int go = to[curS];
                //这条边的权重
                int w = weight[curS];
                distance[go]=Math.min(distance[go],dis+w);
                //处理当前链路上的所有边
                heap.add(new int[]{go, dis + w});
                //处理完后去下一条边
                curS = former[curS];
            }
            cur++;
        }
        //此时distance里面应该是有数据了
        for (int i = 0; i < q; i++) {
            sum+=distance[scanner.nextInt()];
        }
        System.out.println(sum<<1);
    }
    private static void add(int from, int arrive, int w) {
        cnn++;
        //这条边的former指向上一条边
        former[cnn]=curSide[from];
        //这条边的to指向to
        to[cnn]=arrive;
        weight[cnn]=w;
        curSide[from]=cnn;

    }

顺便复习了图:

三种建图方式,第一是二维表,第二十临接表(list套list),第三种就是前向星,主要部分就是

    static int[] curSide ;//代表当前点对应哪条边
    static int[] former;//代表这条边指向的上一条边是哪里
    static int[] to;//这条边的指向
    static int[] weight;//这条边的权重
    static int cnn;//到第几条边了

思路在于:curside[i]是指向的连接自己的某条边,而通过former[i]又能找到上一条,0这个位置不用,当找到0的时候说明这个点的所有边都找完了,找这些边的时候就可以穿插迪克斯拉和Prim算法进去了,迪克斯拉主要是能找到从某个点开头到所有点的距离集合,通过一个点找到这个点的所有边,全部放进小根堆里面去,pop出来一条就处理一条,处理到数目就完成了(还有一种是加强堆,带了个调整,写不动了)。prim是最小生成树,点解锁边,把解锁的边全部放进去小根堆里面,一个个弹出来,全部都处理完了就结束。k算法是全部边放进去小根堆,然后联合并查集,全部都找到之后也结束。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值