2018校招真题【牛客网】练习(八)

1、字节跳动附加题

存在n+1个房间,每个房间依次为房间1 2 3…i,每个房间都存在一个传送门,i房间的传送门可以把人传送到房间pi(1<=pi<=i),现在路人甲从房间1开始出发(当前房间1即第一次访问),每次移动他有两种移动策略:
A. 如果访问过当前房间 i 偶数次,那么下一次移动到房间i+1;
B. 如果访问过当前房间 i 奇数次,那么移动到房间pi;
现在路人甲想知道移动到房间n+1一共需要多少次移动;

思路:
参考 https://blog.csdn.net/flushhip/article/details/79458502
dp[i] = dp[i-1]+1 // 第一次从i-1移动到i
+1 // 从i传送到p[i]位置
+dp[i-1] - dp[ p[i]-1 ] - 1 //从p[i]位置移动到i-1
+ 1 //第二次从i-1移动到i
第三步中:dp[ p[i]-1 ]+1可以理解为,从1到p[i]位置需要移动的步数
代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] p = new int[n+1];
        for(int i=1;i<=n;i++){
            p[i] = scanner.nextInt();
        }
        scanner.close();
        long dp[] = new long[n+1];
        for(int i=1;i<=n;i++){
            dp[i] = (dp[i-1]*2%1000000007-dp[p[i]-1]+2)%1000000007;
        }
        System.out.println(dp[n]%1000000007);
    }
}

2、字节跳动编程题1

题目描述:
有三只球队,每只球队编号分别为球队1,球队2,球队3,这三只球队一共需要进行 n 场比赛。现在已经踢完了k场比赛,每场比赛不能打平,踢赢一场比赛得一分,输了不得分不减分。已知球队1和球队2的比分相差d1分,球队2和球队3的比分相差d2分,每场比赛可以任意选择两只队伍进行。求如果打完最后的 (n-k) 场比赛,有没有可能三只球队的分数打平。

思路:
分类讨论。

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt();
        for(int i=0;i<t;i++){
            boolean isSame = 
                possibleSame(scanner.nextLong(),scanner.nextLong()
                             ,scanner.nextLong(),scanner.nextLong());
            if(isSame){
                System.out.println("yes");
            }else{
                System.out.println("no");
            }
        }
        scanner.close();
    }
    public static boolean possibleSame(long n,long k,long d1,long d2){
        // 1 < 2 < 3
        long temp = k-d1-(d1+d2);
        if(temp>=0&&temp%3==0){
            long left = n-k-(d1+d2+d2);
            if(left>=0&&left%3==0){
                return true;
            }
        }
        // 1 < 2 > 3
        if(d1+d1-d2<0){
            temp = k-(d2+d2-d1);
        }else if(d2+d2-d1<0){
            temp = k-(d1+d1-d2);
        }else{
            temp = k-Math.min(d1+d1-d2,d2+d2-d1);
        }
        if(temp>=0&&temp%3==0){
            long left = n-k-(d1+d2);
            if(left>=0&&left%3==0){
                return true;
            }
        }
        // 1 > 2 > 3
        temp = k-d2-(d1+d2);
        if(temp>=0&&temp%3==0){
            long left = n-k-(d1+d1+d2);
            if(left>=0&&left%3==0){
                return true;
            }
        }
        // 1 > 2 < 3
        temp = k-d1-d2;
        if(temp>=0&&temp%3==0){
            long left = n-k-Math.max(d1+d1-d2,d2+d2-d1);
            if(left>=0&&left%3==0){
                return true;
            }
        }
        return false;
    }
}

3、字节跳动编程题2

题目描述:
有一个仅包含’a’和’b’两种字符的字符串s,长度为n,每次操作可以把一个字符做一次转换(把一个’a’设置为’b’,或者把一个’b’置成’a’);但是操作的次数有上限m,问在有限的操作数范围内,能够得到最大连续的相同字符的子串的长度是多少。

思路:
以替换a为例,那么我们需要找到所有a的位置pos[n],连续的最长的b就是a[i+m+1]-a[i]-1中最长的那一个子序列。

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        scanner.nextLine();
        char[] str = scanner.nextLine().toCharArray();
        System.out.println(Math.max(getLength(n,m,str,'a'),getLength(n,m,str,'b')));
    }
    public static int getLength(int n,int m,char[] str,char c){
        ArrayList<Integer> pos = new ArrayList<>();
        for(int i=0;i<n;i++){
            if(str[i]==c){
                pos.add(i);
            }
        }
        if(pos.size()<=m){
            return n;
        }
        pos.add(str.length);
        int result = pos.get(m);
        for(int i=m+1;i<pos.size();i++){
            result = Math.max(result,pos.get(i)-pos.get(i-m-1)-1);
        }
        return result;
    }
}

4、字节跳动附加题

题目描述:
二阶魔方又叫小魔方,是222的立方形结构。每一面都有4个块,共有24个块。每次操作可以将任意一面逆时针或者顺时针旋转90°,如将上面逆时针旋转90°操作如下。
2018校招真题【牛客网】练习(八)_第1张图片
Nero在小魔方上做了一些改动,用数字替换每个块上面的颜色,称之为数字魔方。魔方上每一面的优美度就是这个面上4个数字的乘积,而魔方的总优美度就是6个面优美度总和。
现在Nero有一个数字魔方,他想知道这个魔方在操作不超过5次的前提下能达到的最大优美度是多少。
魔方展开后每一块的序号如下图:
2018校招真题【牛客网】练习(八)_第2张图片
思路:
参考 https://blog.csdn.net/cswhit/article/details/87110959
写出六个面转动的交换,利用递归求最大值

代码:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNextInt()){
            int[] num = new int[24];
            for(int i=0;i<24;i++){
                num[i] = scanner.nextInt();
            }
            System.out.println(maxGrace(num,5));
        }
    }
    public static int maxGrace(int[] num,int times){
        int grace = calculateGrace(num);
        if(times==0){
            return grace;
        }
        int[] numcp = new int[24];
        for(int i=0;i<24;i++){
            numcp[i] = num[i];
        }
        turnLeft(numcp);
        grace = Math.max(maxGrace(numcp,times-1),grace);
        for(int i=0;i<24;i++){
            numcp[i] = num[i];
        }
        turnRight(numcp);
        grace = Math.max(maxGrace(numcp,times-1),grace);
        for(int i=0;i<24;i++){
            numcp[i] = num[i];
        }
        turnTop(numcp);
        grace = Math.max(maxGrace(numcp,times-1),grace);
        for(int i=0;i<24;i++){
            numcp[i] = num[i];
        }
        turnBottom(numcp);
        grace = Math.max(maxGrace(numcp,times-1),grace);
        for(int i=0;i<24;i++){
            numcp[i] = num[i];
        }
        turnFront(numcp);
        grace = Math.max(maxGrace(numcp,times-1),grace);
        for(int i=0;i<24;i++){
            numcp[i] = num[i];
        }
        turnBack(numcp);
        grace = Math.max(maxGrace(numcp,times-1),grace);
        return grace;
    }
    public static void turnLeft(int[] num){
        change(num,0,6,16,20);
        change(num,2,12,18,22);
        change(num,4,5,11,10);
    }
    public static void turnRight(int[] num){
        change(num,1,7,17,21);
        change(num,3,13,19,23);
        change(num,9,8,14,15);
    }
    public static void turnTop(int[] num){
        change(num,4,6,8,23);
        change(num,5,7,9,22);
        change(num,2,3,1,0);
    }
    public static void turnBottom(int[] num){
        change(num,10,12,14,21);
        change(num,11,13,15,20);
        change(num,16,17,19,18);
    }
    public static void turnFront(int[] num){
        change(num,11,2,8,17);
        change(num,5,3,14,16);
        change(num,6,7,13,12);
    }
    public static void turnBack(int[] num){
        change(num,10,0,9,19);
        change(num,4,1,15,18);
        change(num,22,23,21,20);
    }
    public static void change(int[] num,int i,int j,int k,int m){
        int temp = num[i];
        num[i] = num[j];
        num[j] = num[k];
        num[k] = num[m];
        num[m] = temp;
    }
    
    public static int calculateGrace(int[] n){
        return n[0]*n[1]*n[2]*n[3]
                +n[4]*n[5]*n[10]*n[11]
                +n[8]*n[9]*n[14]*n[15]
                +n[6]*n[7]*n[12]*n[13]
                +n[16]*n[17]*n[18]*n[19]
                +n[20]*n[21]*n[22]*n[23];
    }
}

5、字节跳动编程题1

题目描述:
有一个推箱子的游戏, 一开始的情况如下图:
2018校招真题【牛客网】练习(八)_第3张图片
上图中, ‘.’ 表示可到达的位置, ‘#’ 表示不可到达的位置,其中 S 表示你起始的位置, 0表示初始箱子的位置, E表示预期箱子的位置,你可以走到箱子的上下左右任意一侧, 将箱子向另一侧推动。如下图将箱子向右推动一格;
…S0… -> …S0.
注意不能将箱子推动到’#'上, 也不能将箱子推出边界;
现在, 给你游戏的初始样子, 你需要输出最少几步能够完成游戏, 如果不能完成, 则输出-1。

思路:
参考 https://blog.csdn.net/yuanxu716/article/details/78286266
(还没有完全理解,待以后补充)

代码:

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;

public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNextLine()){
            String[] token = scanner.nextLine().split(" ");
            int n = Integer.parseInt(token[0]);
            int m = Integer.parseInt(token[1]);
            char[][] matrix = new char[n][m];
            int x = -1,y = -1,bx = -1,by = -1;
            for(int i=0;i<n;i++){
                String input = scanner.nextLine();
                for(int j=0;j<m;j++){
                    matrix[i][j] = input.charAt(j);
                    if(matrix[i][j]=='S'){
                        x=i;
                        y=j;
                    }
                    if(matrix[i][j]=='0'){
                        bx=i;
                        by=j;
                    }
                }
            }
            ArrayList<ArrayList<Integer>> next = new ArrayList<>();
            //{-1,0},{1,0},{0,-1},{0,1}
            ArrayList<Integer> a1 = new ArrayList<>();
            a1.add(-1);a1.add(0);
            ArrayList<Integer> a2 = new ArrayList<>();
            a2.add(1);a2.add(0);
            ArrayList<Integer> a3 = new ArrayList<>();
            a3.add(0);a3.add(-1);
            ArrayList<Integer> a4 = new ArrayList<>();
            a4.add(0);a4.add(1);
            next.add(a1);
            next.add(a2);
            next.add(a3);
            next.add(a4);
            //System.out.println(next);
            ConcurrentLinkedQueue<ArrayList<Integer>> queue = new ConcurrentLinkedQueue<>();
            ArrayList<Integer> a = new ArrayList<>();
            a.add(x);a.add(y);a.add(bx);a.add(by);
            queue.offer(a);
            //System.out.println(queue);
            int st[][][][] = new int[50][50][50][50];
            st[x][y][bx][by] = 1;
            while(!queue.isEmpty()){
                ArrayList<Integer> pb = queue.poll();
                x = pb.get(0);
                y = pb.get(1);
                bx = pb.get(2);
                by = pb.get(3);
                for(int i=0;i<next.size();i++){
                    int nx = x+next.get(i).get(0),
                            ny = y+next.get(i).get(1);
                    int nnx = nx+next.get(i).get(0),
                            nny = ny+next.get(i).get(1);
                    // 玩家从开始位置走到箱子的位置
                    if(valid(matrix,nx,ny)&&(nx!=bx||ny!=by)&&st[nx][ny][bx][by]==0){
                        st[nx][ny][bx][by] = st[x][y][bx][by]+1;
                        ArrayList<Integer> list = new ArrayList<>();
                        list.add(nx);list.add(ny);list.add(bx);list.add(by);
                        queue.offer(list);
                        continue;
                    }
                    // 玩家把箱子推到指定位置
                    else if(valid(matrix,nnx,nny)&&(nx==bx&&ny==by)&&st[nx][ny][nnx][nny]==0){
                        st[nx][ny][nnx][nny] = st[x][y][bx][by]+1;
                        if(matrix[nnx][nny]=='E'){
                            System.out.println(st[nx][ny][nnx][nny]-1);
                            return;
                        }
                        ArrayList<Integer> list = new ArrayList<>();
                        list.add(nx);list.add(ny);list.add(nnx);list.add(nny);
                        queue.offer(list);
                    }
                }

            }
            System.out.println(-1);
            return;
        }
    }
    public static boolean valid(char[][] matrix,int x,int y){
        if (x >= 0 && x < matrix.length && y >= 0 && y < matrix[0].length && matrix[x][y] != '#')
            return true;
        return false;
    }
}

你可能感兴趣的:(2018校招真题,算法,牛客网)