[字节跳动]2018秋招算法题【持续更新中】

本文探讨了多项复杂算法挑战,包括世界杯开幕式球迷群体统计、编辑病句合并、游戏策略制定、序列区间比较、直播观看优化、红人识别等问题。通过对这些场景的深入分析,提供了解决方案,并涉及了数据结构、算法设计、信息处理等多个关键领域。

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

  1. 世界杯开幕式会在球场C举行,球场C的球迷看台可以容纳M*N个球迷。在球场售票完成后,现官方想统计此次开幕式一共有多少个球队球迷群体,最大的球队球迷群体有多少人。

经调研发现,球迷群体在选座时有以下特性:

同球队的球迷群体会选择相邻座位,不同球队的球迷群体会选择不相邻的座位(注解:相邻包括前后相邻,左右相邻,斜对角相邻)

给定一个M*N的二维球场,0代表该位置没有坐人,1代表该位置已有选择,希望输出球队群体个数P,最大的球队群体人数Q

输入描述:

第一行,2个数字,M及N,使用英文逗号分隔

接下来M行,每行N的数字,使用英文逗号分隔

输出描述:

一行,2个数字,P及Q,使用英文逗号分隔

其中P表示球队群体个数,Q表示最大的球队群体人数

例:输入

10,10

0,0,0,0,0,0,0,0,0,0

0,0,0,1,1,0,1,0,0,0

0,1,0,0,0,0,0,1,0,1

1,0,0,0,0,0,0,0,1,1

0,0,0,1,1,1,0,0,0,1

0,0,0,0,0,0,1,0,1,1

0,1,1,0,0,0,0,0,0,0

0,0,0,1,0,1,0,0,0,0

0,0,1,0,0,1,0,0,0,0

0,1,0,0,0,0,0,0,0,0

输出:6,8

	import java.util.Scanner;
	
	public class BallFan {
	    public static int m = 0;
	    public static int n = 0;
	    public static int total = 0;
	
	    public static void main (String[] args){
	        Scanner sc = new Scanner(System.in);
	        String[] m_n = sc.nextLine().split(",");
	        m = Integer.parseInt(m_n[0]);//行
	        n = Integer.parseInt(m_n[1]);//列
	        if (m <= 0 || n <= 0) return;
	
	        int[] arr = new int[n*m + 1];//用一维数组存储
	        int i = 1;
	        for(int j=0; j < m; j++){
	            String[] line = sc.nextLine().split(",");
	            for (int k=0; k < n; k++){
	                arr[i] = Integer.parseInt(line[k]);
	                i++;
	            }
	        }
	
	        int groups = 0;//组数
	        int max = 0;//最大人数
	        for (int j=1; j <= n*m; j++){
	            if (arr[j] == 0) continue;
	
	            groups++;
	            total = 0;
	            //递归求解
	            countMumber(arr, j);
	
	            if (total > max)
	                max = total;
	
	        }
	
	        System.out.println(groups + "," + max);
	
	    }
	
	    public static void countMumber (int[]arr, int poi){
	
	        if (arr[poi] == 0) return;
	
	        arr[poi] = 0;
	        total++;
	
	        //确定当前游标位置,根据游标位置取方位值
	        if (poi % n != 0){//最右并不需要向右边寻值,我们可以认为是一个从左到右的过程
	            countMumber(arr, poi+1);
	        }
	        if (poi % n != 1){//最左并不需要向左边寻值
	            countMumber(arr, poi-1);
	        }
	
	        if (n*m - n > poi){//不位于下边界即可向下探索
	            int down = poi + n;
	            countMumber(arr, down);//向下寻值
	
	            if (down % n != 0){//非最右
	                countMumber(arr, down+1);//下右对角线
	            }
	
	            if (down % n != 1){//非最左
	                countMumber(arr, down-1);//下左对角线
	            }
	
	        }
	        if (n < poi){
	            int up = poi - n;
	            countMumber(arr, up);//向上寻值
	
	            if (up % n != 0){//非最右
	                countMumber(arr, up+1);//上右对角线
	            }
	
	            if (up % n != 1){//非最左
	                countMumber(arr, up-1);//上左对角线
	            }
	        }
	
	    }
	
	}
  1. 为了提高文章质量,每一篇文章(假设全部都是英文)都会有m名编辑进行审核,每个编辑独立工作,会把觉得有问题的句子通过下表记录下来,比如[1,10],1表示病句的第一个字符,10表示病句的最后一个字符。也就是从1到10着10个字符组成的句子,是有问题的。

现在需要把多名编辑有问题的句子合并起来,送个总编辑进行最终的审核。比如编辑A指出的病句是[1,10],[32,45];编辑B指出的病句是[5,16],[78,94]那么[1,10]和[5,16]是有交叉的,可以合并成[1,16][32,45][78,94]

输入描述:

编辑数量m,之后每行是每个编辑的标记的下表组合,第一个和最后一个下标用英文逗号分隔,每组下标之间用分号分隔

输出描述:

合并后的下标集合,第一个和最后一个下标用英文逗号分隔,每组下标之间用分号分隔。返回结果是从小到大递增排列

例:输入

3

1,10;32,45

78,94;5,16

80,100;200,220;16,32

输出: 1,45;78,100;200,220

	package test2;
	
	import java.util.*;
	public class ErrTopic {
	
	    public static void main (String[] args) {
	        Scanner sc = new Scanner(System.in);
	        int lines = Integer.parseInt(sc.nextLine());
	        HashMap <Integer,Integer> hs = new HashMap<>();
	
	        int groups = 1;
	        for (int i=0; i < lines; i++){
	            String[] finds = sc.nextLine().split(";");
	            for (String area: finds){
	                String[] deatil = area.split(",");
	                int begin = Integer.parseInt(deatil[0]);
	                int end = Integer.parseInt(deatil[1]);
	                hs.put(begin, end);
	                groups++;
	            }
	        }
	
	        int[] arr = new int[(groups-1)*2];
	        int k = 0;
	        for (Integer i: hs.keySet()){
	            arr[k] = i;
	            arr[k+1] = hs.get(i);
	            k += 2;
	        }
	        Arrays.sort(arr);//升序排列
			 
	        int begin = arr[0];//启动组编号
	        int end = hs.get(begin);//截至组编号
	        int current;//当前位置
	        String result = "";
	        for (int i=1; i < arr.length; i++){
	            current = arr[i];
	
	            if (hs.get(current) != null){//证明current是一个起始位
	                int comp = hs.get(current);
	                end = comp > end ?comp: end;
	                continue;
	            }else if(current == end){
	
	                if (result != ""){
	                    result += ";";
	                }
	                result += begin + "," + end;
	
	                if (i+1 < arr.length) {
	                    begin = arr[i + 1];
	                    end = hs.get(begin);
	                }
	            }
	
	
	        }
	
	        System.out.println(result);
	
	    }
	
	}
  1. 小a和小b玩一个游戏,有n张卡牌,每张上面有两个正整数x,y。取一张牌时,个人积分增加x,团队积分增加y。求小a,小b各取若干张牌,使得他们的个人积分相等,且团队积分最大。
    用例描述:

输入:
4 # n=4 组数据
3 1 # x, y
2 2
1 4
1 4
输出:10

import java.util.Scanner;

public class MaxTearmCard {

    public static void main (String[] args){
        Scanner sc = new Scanner(System.in);
        int count = sc.nextInt();
        int[] person_score = new int[count+1];//记录一张卡片的个人分数
        int[] team_score = new int[count+1];//记录一张卡片的团队分数
        int max = 0;

        for (int i=1; i <= count; i++){
            person_score[i] = sc.nextInt();
            team_score[i] = sc.nextInt();
            max = max > person_score[i] ? max : person_score[i];
        }

        //i行第j列表示,从第1张牌到第n张牌的最大团队收益
        //这里之所以使用max是a抽到的牌比b的最大值
        //也可以不使用max而改用person_score所有值的和,但没必要
        int[][] teamMax = new int[count+1][max+1];
        getTeamMax(teamMax, max, person_score, team_score);
//        for (int i=0; i < count+1; i++){
//            for (int j=0; j < max+1; j++)
//                System.out.print(teamMax[i][j] + " ");
//            System.out.println();
//        }
        System.out.println(teamMax[count][0]);
        sc.close();

    }

    public static void getTeamMax (int[][] teamMax, int max,
                                   int[] pesron_score, int[] team_score) {

        //只需要考虑a比b的情况,二者是对称的
        for (int i=1; i < teamMax.length; i++){//外层控制a-b的差值

            for (int j=0; j <= max; j++){//内层控制选择到第i张牌
                if (i == 1 && j == 0)
                    continue;//只有一张牌差值为0的情况不存在,跳过


                int aGetMax = 0;//a获取第i张牌后当前团队最大积分
                int aLostMax = 0;//b获取第i张牌后当前团队最大积分

                //假设a在接受第i张牌前,只比b大j-pesron_score[i]
                //即把第i张牌分配给a的情况
                if (j - pesron_score[i] >= 0){
                    aGetMax = teamMax[i-1][j-pesron_score[i]]
                            + team_score[i];
                }

                //把第i张牌给b的情况,即a-b差值从j+person_score[i]减到j
                if(j + pesron_score[i] <= max){
                    aLostMax = teamMax[i-1][j+pesron_score[i]]
                            + team_score[i];
                }

                //teamMax[i-1][j]代表谁也不分配牌的情况
                teamMax[i][j] = Math.max(Math.max(aGetMax, aLostMax), teamMax[i-1][j]);

            }

        }


    }


}
  1. 两个长度为n的序列a,b。问a中有多少个区间[l,r]满足max(a[l,r])<min(b[l,r])
    即a区间的最大值小于b区间的最小值数据范围:n<1e5,a(i),b(i)<1e9
    输入描述:
    第一行一个整数n
    第二行n个数,第i个为a(i)
    第三行n个数,第i个为b(i)
    0<1<=r<n
    输出描述:
    一行一个整数,表示答案
    例1:输入
    3
    3 2 1
    3 3 3
    输出: 3

     import java.util.*;
     public class CompAbArea {
     
         //思路:
         //1. 对a组合使用map进行虑重
         //2. 对b使用set进行虑重
         //3. 将a虑重结果放入list中
         //4. 比较ab
         public static void main (String[] args) {
             Scanner sc = new Scanner(System.in);
             int n = sc.nextInt();//a和b的元素个数都为n
             int[] a = new int[n];
             HashSet<Long> bSet = new HashSet<>();
     
             for (int i=0; i < n; i++)
                 a[i] = sc.nextInt();
             for (int i=0; i < n; i++)
                 bSet.add(sc.nextLong());
     
     
             HashMap<String, Long> hs = new HashMap<>();
             for(int i=0; i < n; i++){//外层控制增量
                 int lf = 0;//左边界
                 int rt = lf + i;//右边界
                 while (rt < n){
                     long max = a[lf];
                     String str = "";
                     for(int k=lf; k <= rt; k++) {
                         max = max > a[k] ? max : a[k];
                         if(str != "")
                             str += ",";
                         str += a[k];
                     }
                     lf = lf+1;
                     rt = lf+i;
     
                     hs.put(str, max);//采用map过滤重复顺序
     
                 }
     
             }
     
             List<Long> maxLs = new ArrayList<>();
             for(long v : hs.values()){
                 maxLs.add(v);
             }
     
             int result = 0;
             for (int i=0; i < maxLs.size(); i++){
                 Iterator<Long> ite = bSet.iterator();
                 while(ite.hasNext()){
                     if(ite.next() > maxLs.get(i)){
                         result++;
                         break;
                     }
                 }
     
             }
     
             System.out.println(result);
     
     
         }
     
     }
    
  2. 小明在抖音里关注了N个主播,每个主播每天的开播时间是固定的,分别在S时刻开始开播,t时间结束。小明无法同时观看两个主播的直播。一天被分成了M个时间单位。请问小明每天最多能完整观看多少场直播?
    输入描述:
    第一行一个整数,代表N
    第二行一个整数,代表M
    第三行空格间隔的N*2个整数,代表s,t
    输出描述:
    一行一个整数,表示答案
    例1:输入
    3
    10
    0 3 3 7 7 0
    输出:3
    例2: 输入
    3
    10
    0 5 2 7 6 9
    输出:2
    备注:数据范围1<=N<=10^5
    2<=M<=10^6
    0<=s(i),t(i)<M (s(i)!=t(i))
    s(i)>t(i)代表时间跨天,但直播时长不会超过一天

     import java.util.*;
     public class MaxLive {
     
         //思路:从某一区间出发,向右吞并
         public static void main (String[] args){
     
             Scanner sc = new Scanner(System.in);
             int n = sc.nextInt();
             int m = sc.nextInt();
             List<Live> ls = new ArrayList<>(n);
             for (int i=0; i < n; i++){
                 int start = sc.nextInt();
                 int end = sc.nextInt();
                 ls.add(new Live(start, end));
             }
     
             //先排序链表
             Collections.sort(ls, new LiveComparator());
     
             //开始执行吞并
             int max = 0;
             for (int i=0; i < n; i++){
                 int lf = ls.get(i).start;
                 int rt = ls.get(i).end;
                 int total = 1;
     
                 for(int j=(i+1)%n;  j!=i; j=(j+1)%n){
                     int cs = ls.get(j).start;
                     int ce = ls.get(j).end;
     
                     if (rt <= cs && cs <= ce
                         || rt <= cs && ce <= lf
                         || ce <= cs && cs <= lf) {
                         rt = ce;
                         total++;
                     }
     
                 }
     
                 max = max > total ? max : total;
     
             }
     
             System.out.println(max);
     
         }
     
     
         public static class Live{
             int start;
             int end;
     
             public Live(int start, int end) {
                 this.start = start;
                 this.end = end;
             }
     
             @Override
             public String toString() {
                 return "Live{" +
                         "start=" + start +
                         ", end=" + end +
                         '}';
             }
         }
     
         public static class LiveComparator implements Comparator<Object>{
     
             @Override
             public int compare(Object o1, Object o2) {
                 Live l1 = (Live)o1;
                 Live l2 = (Live)o2;
                 int c1 = l1.start - l2.start;
                 if (c1 == 0){
                      if(l1.start > l1.end && l1.start > l2.end)//出现两个跨天
                          return -(l1.end - l2.end);
                      if(l1.start > l1.end && l1.start <= l2.end){//单个跨天
                          return 1;
                      }
                     if(l1.start > l2.end && l1.start <= l1.end){//单个跨天
                         return -1;
                     }
                     return l1.end - l2.end;
                 }
     
                 return c1;
             }
         }
     
     }
    
  3. 抖音工程师想要找到抖音里的红人。
    假设用户数为N,有M个关注关系对(A,B)。
    (A,B)表示用户A关注了用户B,关注关系具有传递性,
    例如:用户A关注了用户B,用户B关注了用户C,那么A间接关注了C.
    如果一个用户被N个用户直接或间接关注,
    那么我们认为这个用户是抖音红人。求抖音红人的总数
    输入描述:
    第一行一个整数,代表N
    第二行一个整数,代表M
    第三行空格分隔的M*2个整数,代表关注关系对
    输出描述:
    一行一个整数,表示答案
    如:
    输入
    3
    3
    1 2 2 1 2 3
    1

     	import java.util.*;
     	
     	public class HotMan {
     	    //注意:这题有一个坑,即默认自己关注自己,因此要算的是关注人数 >= N-1即可
     	    public static void main (String[] args){
     	        Scanner sc = new Scanner(System.in);
     	        int n = sc.nextInt();//关注个数
     	        int m = sc.nextInt();//关系对数
     	        HashMap<Integer, HashSet<Integer>> hs = new HashMap<>(n);
     	
     	        for (int i=0; i < m; i++){
     	            int a = sc.nextInt();//关注者
     	            int b = sc.nextInt();//被关注者
     	
     	            HashSet<Integer> set = new HashSet<>();//关注者名单
     	            if (hs.get(b) != null) {
     	                set = hs.get(b);
     	            }
     	            set.add(a);
     	            hs.put(b, set);
     	        }
     	
     	        int count = 0;
     	        for(Integer b : hs.keySet()) {
     	            HashMap<Integer, Integer> total = new HashMap<>();
     	            findRelation(hs, total, b);
     	            if (total.size()>= n)
     	                count++;
     	        }
     	
     	        System.out.println(count);
     	
     	
     	    }
     	
     	    public static void findRelation (HashMap<Integer,HashSet<Integer>> hs,
     	                                     HashMap<Integer, Integer> total, int num){
     	
     	        if (total.get(num) != null) return;
     	        total.put(num, 1);
     	
     	        HashSet<Integer> set = hs.get(num);
     	        Iterator<Integer> ite = set.iterator();
     	        while(ite.hasNext()){
     	            int i = ite.next();
     	            if (total.get(i) != null)
     	                continue;
     	            findRelation(hs, total, i);
     	        }
     	
     	    }
     	
     	
     	}
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值