携程4.16笔试

第二道:三个数组abc,游游打算重排c数组,使得尽可能多的下标i满足ai+bi=ci。

思路:ai+bi的值是固定的 先用一个for循环算一遍 放到map里 ,key是值,value是个数,然后再用一个for循环 看看数组c里的值有没有在map里出现,有的话 计数+1,并且让map里相应的key 值-1 然后就好了。

第三题:给一个数组,每次操作可以把相邻的两个素数元素进行合并,合并后的新数为原来的两个数之和,并删除原来两个数。现在希望最终数组的元素数量尽可能少。

第一行输入n表示数组大小,第二行输入n个正整数,表示数组元素。

思路:

1.写一个检查是否是素数的函数

2.写一个合并函数:

2.1先判断2 这个特殊情况 因为素数2和相邻的素数合并 结果可能是素数也可能是非素数 别的素数合并都是非素数。所以要先判断存不存在2和相邻的一边的素数合并是素数 另一边合并不是素数的情况 比如数组7 2 3 后两个先合并和前两个先合并就不一样。

2.2再把其余素数合并

代码:

import java.util.ArrayList;  
import java.util.List;  
import java.util.Scanner;  
  
public class PrimeMerge {  
    public static void main(String[] args) {  
        Scanner scanner = new Scanner(System.in);  
        int n = scanner.nextInt();  
        List<Integer> numbers = new ArrayList<>();  
  
        // 读取数组元素  
        for (int i = 0; i < n; i++) {  
            numbers.add(scanner.nextInt());  
        }  
  
        // 关闭Scanner  
        scanner.close();  
  
        // 合并素数,优先处理2  
        mergePrimesWithPriorityToTwo(numbers);  
  
        // 输出最终数组  
        for (int num : numbers) {  
            System.out.print(num + " ");  
        }  
    }  
  
    private static void mergePrimesWithPriorityToTwo(List<Integer> numbers) {  
        // 检查一个数是否是素数的辅助函数  
        boolean isPrime(int num) {  
            if (num <= 1) return false;  
            for (int i = 2; i * i <= num; i++) {  
                if (num % i == 0) {  
                    return false;  
                }  
            }  
            return true;  
        }  
  
        // 合并2与其相邻的素数  
        for (int i = 0; i < numbers.size(); ) {  
            if (numbers.get(i) == 2) {  
                // 检查左边是否有素数可以合并  
                if (i > 0 && isPrime(numbers.get(i - 1)) && isPrime(numbers.get(i - 1) + 2)) {  
                    numbers.set(i - 1, numbers.get(i - 1) + 2);  
                    numbers.remove(i);  
                } else if (i < numbers.size() - 1 && isPrime(numbers.get(i + 1)) && isPrime(numbers.get(i + 1) + 2)) {  
                    // 检查右边是否有素数可以合并  
                    numbers.set(i, numbers.get(i) + numbers.get(i + 1));  
                    numbers.remove(i + 1);  
                } else {  
                    // 没有可以合并的素数,继续下一个数  
                    i++;  
                }  
            } else {  
                i++;  
            }  
        }  
  
        // 合并剩余的素数对  
        for (int i = 0; i < numbers.size() - 1; ) {  
            if (isPrime(numbers.get(i)) && isPrime(numbers.get(i + 1)))) {  
                numbers.set(i, numbers.get(i) + numbers.get(i + 1));  
                numbers.remove(i + 1);  
            } else {  
                i++;  
            }  
        }  
    }  
}

第四题:定义一棵树的直径为:任意两个节点的距离的最大值。现在定义f(i):对i号节点上再连接一个新的子叶节点后,树的直径长度。现在要求f(1)到f(n)的值。

输入描述:第一行输入一个正整数n,代表树的节点数量。

接下来的n-1行,每行输入两个正整数u和v,代表u号节点和v号节点之间有一条长度为1的边连接。

变量的范围:1≤n≤10的五次方,1≤u,v≤n。

思路:第四题说是树的直径,但其实就是图,但是可以用二叉树类比着来做。

1.写一个树类,val表示节点编号,children表示孩子链表。把每个节点创建处理并保存,把每个节点的孩子节点添加一下。

2.写一个for循环,针对每个f(i),把新的子叶节点添加一下,然后调用dfs处理得到f(i)值。

3.dfs:二叉树求直径实际上是求子树的深度,然后左右子树深度相加就是直径,返回结果是左右子树深度的最大值+1。同样的道理,这里也是求所有子树的深度,记录最大深度和第二大深度,然后f(i)就是最大深度和第二大深度之和,返回结果就是最大深度+1。

代码:

import java.util.*;


class TreeNode {
    int val;
    List<TreeNode> children;
    
    public TreeNode(int val) {
        this.val = val;
        children = new ArrayList<>();
    }
}


public class TreeDiameter {
    public static int[] f; // 存储每个节点的f(i)值
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(); // 树的节点数量
        
        f = new int[n + 1]; // 初始化f数组
        
        // 构建树的数据结构
        TreeNode[] nodes = new TreeNode[n + 1];
        for (int i = 1; i <= n; i++) {
            nodes[i] = new TreeNode(i);
        }
        
        // 连接节点之间的关系
        for (int i = 0; i < n - 1; i++) {
            int u = scanner.nextInt();
            int v = scanner.nextInt();
            nodes[u].children.add(nodes[v]);
            nodes[v].children.add(nodes[u]);
        }
        
        // 遍历每个节点,添加一个新的子叶节点,计算f(i)
        for (int i = 1; i <= n; i++) {
            // 添加新的子叶节点
            addLeafAndDFS(nodes[i], n + i);
            // 计算f(i)
            dfs(nodes[i], null, i);
        }
        
        // 输出结果
        for (int i = 1; i <= n; i++) {
            System.out.print(f[i] + " ");
        }
    }
    
    // 添加新的子叶节点,并调用dfs计算f(i)
    public static void addLeafAndDFS(TreeNode node, int newLeafValue) {
        TreeNode newLeaf = new TreeNode(newLeafValue); // 创建新的子叶节点
        node.children.add(newLeaf); // 添加到当前节点的子节点中
        newLeaf.children.add(node); // 添加当前节点作为新的子叶节点的父节点
    }
    
    // 递归计算以当前节点为根的子树的直径
    public static void dfs(TreeNode node, TreeNode parent, int i) {
        int maxDepth1 = 0; // 最大深度
        int maxDepth2 = 0; // 次大深度
        
        // 遍历当前节点的子节点
        for (TreeNode child : node.children) {
            if (child == parent) continue; // 避免回溯
            int childDepth = dfs(child, node, i); // 递归计算子节点的深度
            if (childDepth > maxDepth1) {
                maxDepth2 = maxDepth1;
                maxDepth1 = childDepth;
            } else if (childDepth > maxDepth2) {
                maxDepth2 = childDepth;
            }
        }
        
        // 更新f(i)
        f[i] = Math.max(f[i], maxDepth1 + maxDepth2);
    }
}

#我的实习求职记录#
全部评论
这个第四题这样不超时吗
2 回复
分享
发布于 04-16 21:32 上海
这就叫专业
1 回复
分享
发布于 04-16 21:25 山东
联易融
校招火热招聘中
官网直投
点赞 回复
分享
发布于 04-16 21:23 陕西
你在搞笑吗?那7 3 2 怎么办?7和3也是素数合并了却是合数啊
点赞 回复
分享
发布于 04-16 21:43 江苏
nb
点赞 回复
分享
发布于 04-16 22:08 浙江
捉校友 佬
点赞 回复
分享
发布于 04-16 22:43 吉林
唉,三四都没做出来😅寄了寄了
点赞 回复
分享
发布于 04-16 22:49 陕西
第四题感觉有点困惑,按你的做法的话,计算后续f(3)、f(4)的时候前面计算f(1)的时候添加的新节点也会产生影响吧,但题目问的应该是f(i)应该是只考虑在i这个节点上新增一个边
点赞 回复
分享
发布于 04-17 08:30 辽宁

相关推荐

6 21 评论
分享
牛客网
牛客企业服务