字节跳动春招研发部分编程题汇总做题笔记---Java

3.雀魂启动!

小包最近迷上了一款叫做雀魂的麻将游戏,但是这个游戏规则太复杂,小包玩了几个月了还是输多赢少。
于是生气的小包根据游戏简化了一下规则发明了一种新的麻将,只留下一种花色,并且去除了一些特殊和牌方式(例如七对子等),具体的规则如下:

总共有36张牌,每张牌是1~9。每个数字4张牌。
你手里有其中的14张牌,如果这14张牌满足如下条件,即算作和牌
14张牌中有2张相同数字的牌,称为雀头。
除去上述2张牌,剩下12张牌可以组成4个顺子或刻子。顺子的意思是递增的连续3个数字牌(例如234,567等),刻子的意思是相同数字的3个数字牌(例如111,777)

例如:

1 1 1 2 2 2 6 6 6 7 7 7 9 9 可以组成1,2,6,7的4个刻子和9的雀头,可以和牌
1 1 1 1 2 2 3 3 5 6 7 7 8 9 用1做雀头,组123,123,567,789的四个顺子,可以和牌
1 1 1 2 2 2 3 3 3 5 6 7 7 9 无论用1 2 3 7哪个做雀头,都无法组成和牌的条件。

现在,小包从36张牌中抽取了13张牌,他想知道在剩下的23张牌中,再取一张牌,取到哪几种数字牌可以和牌。

输出描述:

输出同样是一行,包含1个或以上的数字。代表他再取到哪些牌可以和牌。若满足条件的有多种牌,请按从小到大的顺序输出。若没有满足条件的牌,请输出一个数字0

示例1

输入例子:
1 1 1 2 2 2 5 5 5 6 6 6 9
输出例子:
9
例子说明:
可以组成1,2,6,7的4个刻子和9的雀头

示例2

输入例子:
1 1 1 1 2 2 3 3 5 6 7 8 9
输出例子:
4 7
例子说明:
用1做雀头,组123,123,567或456,789的四个顺子

示例3

输入例子:
1 1 1 2 2 2 3 3 3 5 7 7 9
输出例子:
0

思路

遍历可加的九个数,然后进行递归判断。

ac代码
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int[] card = new int[10];
        for (int i=0;i<13;i++)
            card[in.nextInt()]++;
        ArrayList<Integer> result = new ArrayList<>();
        for (int i=1;i<10;i++){
            if(card[i]>3)
                continue;
            card[i]++;
            if(findRight(card))
                result.add(i);
            card[i]--;
        }
        for (int x:result)
            System.out.print(x+" ");
    }

    public static boolean findRight(int[] card){
        boolean flog = false;
        for (int i=1;i<10;i++){
            // to delete que
                if (card[i]<2)
                    continue;
                card[i]-=2;
                PriorityQueue<Integer> cards = new PriorityQueue<>();
                 Add(cards,card);
                flog = proveRight(cards,card);
                card[i]+=2;
                if (flog)
                    return true;
        }
        return false;
    }

    public static boolean proveRight(PriorityQueue<Integer> cards,int[] card){

        if (cards.isEmpty())
            return true;
        boolean flog = false;
        int now = cards.peek();
            if (card[now]>=3){
                for(int i=0;i<3;i++)
                cards.poll();
                card[now]-=3;
                flog = proveRight(cards,card);
                for(int i=0;i<3;i++)
                cards.add(now);
                card[now]+=3;
            }
            if (flog)
                return flog;
            if (now<=7&&card[now+1]!=0&&card[now+2]!=0)
            {
                for(int i=0;i<3;i++)
                {
                    card[now+i]-=1;
                    cards.remove(now+i);
                }
                flog = proveRight(cards,card);
                for(int i=0;i<3;i++)
                {
                    card[now+i]+=1;
                    cards.add(now+i);
                }
            }
            return flog;
    }
    public static void Add(PriorityQueue<Integer> cards,int[] card){
        for (int i=1;i<10;i++){
            for (int x=1;x<=card[i];x++)
                cards.add(i);
        }
    }
}

4.特征提取

小明是一名算法工程师,同时也是一名铲屎官。某天,他突发奇想,想从猫咪的视频里挖掘一些猫咪的运动信息。为了提取运动信息,他需要从视频的每一帧提取“猫咪特征”。一个猫咪特征是一个两维的vector<x, y>。如果x_1=x_2 and y_1=y_2,那么这俩是同一个特征。
因此,如果喵咪特征连续一致,可以认为喵咪在运动。也就是说,如果特征<a, b>在持续帧里出现,那么它将构成特征运动。比如,特征<a, b>在第2/3/4/7/8帧出现,那么该特征将形成两个特征运动2-3-4 和7-8。
现在,给定每一帧的特征,特征的数量可能不一样。小明期望能找到最长的特征运动。
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M
输入描述:
第一行包含一个正整数N,代表测试用例的个数。

每个测试用例的第一行包含一个正整数M,代表视频的帧数。

接下来的M行,每行代表一帧。其中,第一个数字是该帧的特征个数,接下来的数字是在特征的取值;比如样例输入第三行里,2代表该帧有两个猫咪特征,<1,1>和<2,2>
所有用例的输入特征总数和<100000

N满足1≤N≤100000,M满足1≤M≤10000,一帧的特征个数满足 ≤ 10000。
特征取值均为非负整数。

输出描述:

对每一个测试用例,输出特征运动的长度作为一行
示例1

输入例子:

1
8
2 1 1 2 2
2 1 1 1 4
2 1 1 2 2
2 2 2 1 4
0
0
1 1 1
1 1 1

输出例子:

3

例子说明:

特征<1,1>在连续的帧中连续出现3次,相比其他特征连续出现的次数大,所以输出3.

思路

记录帧的所有值,并用一个map保存上一次的帧值,主要技巧在,用String保存两个long数据(其实根据题意无法判断long是否够存,所幸够,要不然在找值的时候需要再堆字符串进行处理)。

ac代码

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int p = in.nextInt();
        while(p-->0){
            int n = in.nextInt();
            int max = Integer.MIN_VALUE;
            HashMap<String,Integer> before = new HashMap<>();
            HashMap<String,Integer> now = new HashMap<>();
            while(n-->0){
                int m = in.nextInt();
                for (int i=0;i<m;i++)
                {
                    long x = in.nextLong();
                    long y = in.nextLong();
                    String now_key = String.valueOf(x)+" "+String.valueOf(y);
                    int now_value = before.getOrDefault(now_key,0)+1;
                    max = Math.max(now_value,max);
                    now.put(now_key,now_value);
                }
                before.clear();
                before.putAll(now);
                now.clear();
                }
            System.out.println(max);
        }
    }
}

5.毕业旅行问题(没做出来,思路贴了参考答案)

小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北京,每个城市之间均乘坐高铁,且每个城市只去一次。由于经费有限,希望能够通过合理的路线安排尽可能的省一些路上的花销。给定一组城市和每对城市之间的火车票的价钱,找到每个城市只访问一次并返回起点的最小车费花销。
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M
输入描述:
城市个数n(1<n≤20,包括北京)

城市间的车票价钱 n行n列的矩阵 m[n][n]

输出描述:

最小车费花销 s
示例1

输入例子:

4
0 2 6 5
2 0 4 4
6 4 0 2
5 4 2 0

输出例子:

13

例子说明:

共 4 个城市,城市 1 和城市 1 的车费为0,城市 1 和城市 2 之间的车费为 2,城市 1 和城市 3 之间的车费为 6,城市 1 和城市 4 之间的车费为 5,依次类推。假设任意两个城市之间均有单程票可购买,且票价在1000元以内,无需考虑极端情况。

思路

本来想的是进行回溯,后来计算复杂度是n的阶乘,肯定超时,但是没想到好的方法,找到了一个解析是用dp的这里贴一下解答
思路就是用dp记录做每次加入单个城市路径的记录。
复杂度是O(2的n次方n的平方)
n最大20,10的六次方
400 超时边界,基本不会超时。

ac代码
import java.util.*;
 
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
      public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[][] road = new int[n][n];
        for (int i=0;i<n;i++)
            for (int j=0;j<n;j++)
                road[i][j] = in.nextInt();
        // dp[i][j] ,replace the distance of  i to(j) until 0;
        int[][] dp = new int[n][1<<(n-1)];
        for (int i=1;i<n;i++)
            dp[i][0] = road[i][0];
 
        for (int p=1;p<1<<(n-1);p++){
            for (int i=0;i<n;i++){
                dp[i][p] = Integer.MAX_VALUE>>1;
                if (is_p(i,p))
                    continue;
                for (int now=1;now<n;now++){
                    if (is_p(now,p)){
                        int before = find(now,p);
                        dp[i][p] = Math.min(dp[i][p],dp[now][before]+road[i][now]);
                    }
                }
            }
        }
        System.out.println(dp[0][(1<<(n-1))-1]);
    }
 
    public static boolean is_p(int i,int p){   // 0 (为起始或者中间) 这件事一直都对
            return  ((1<<(i-1))&p)!=0;
    }
    public static int find(int i,int p){
//        return (p & (~(1 << (i - 1))));
        return p-(1<<(i-1));
    }
     
}

7

思路:反向求解
如果是H(k+1) > E ,假设跳跃后为E_2,有 E_2 = E - (H(k+1) - E) = 2E - H(K+1);
如果是H(k+1) <= E,假设跳跃后为E_2,有 E_2 = E + (E - H(k+1)) = 2E - H(K+1);
无论哪种情况,最终都有 E_2 = 2E - H(K+1); -> E = (E_2 + H(k+1) + 1)/2 -> 加一是为了向上取整。

import java.util.Scanner;
 
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n];
        for(int i=0;i<n;i++)
            nums[i] = in.nextInt();
        long result = 0;
        for(int i=n-1;i>=0;i--){
            result = (result+nums[i]+1)/2;
        }
        System.out.println(result);
}
}
  • 30
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023年3月11日,美团春季招聘笔试中共包含五道编程题目。以下是对每道题目的简要说明: 1. 题目一:这道题目要求解决一个数字统计的问题。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问题的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 题目二:这道题目可能是一个字符串处理的问题。需要使用字符串的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 题目三:这道题目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问题。解决思路可能包括遍历、递归、搜索和排序等。 4. 题目四:这道题目可能是一个动态规划的问题。需要根据给定的条件和规则,通过动态规划的方式求解问题。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 题目五:这道题目可能是一个图论或网络问题。需要根据给定的图或网络结构,解决一个相关的问题。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程题目的一些可能情况进行的简要描述,具体的题目内容可能会有所不同。希望这些信息能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值