校招算法笔面试 | 校招笔面试真题-图的遍历

题目## 题目

题目链接

解题思路

这是一个无向图遍历问题:

  1. 1 1 1 号节点出发,需要遍历所有节点
  2. 每条边长度为 1 1 1
  3. 需要找到最短的遍历路径

关键发现:

  1. 对于叶子节点,必须走两次(来回)
  2. 对于非叶子节点,只需要走一次就能到达其他节点
  3. 最小路程 = 2 2 2 * (边数) - (最远叶子节点的深度)

代码

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int maxDepth = 0;  // 记录最远叶子节点的深度

void dfs(vector<vector<int>>& graph, vector<bool>& visited, int curr, int depth) {
    visited[curr] = true;
    
    bool isLeaf = true;
    for(int next : graph[curr]) {
        if(!visited[next]) {
            isLeaf = false;
            dfs(graph, visited, next, depth + 1);
        }
    }
    
    if(isLeaf) {
        maxDepth = max(maxDepth, depth);
    }
}

int main() {
    int n;
    cin >> n;
    
    // 构建邻接表
    vector<vector<int>> graph(n + 1);
    for(int i = 0; i < n - 1; i++) {
        int x, y;
        cin >> x >> y;
        graph[x].push_back(y);
        graph[y].push_back(x);
    }
    
    // DFS找最远叶子节点
    vector<bool> visited(n + 1, false);
    dfs(graph, visited, 1, 0);
    
    // 计算结果
    cout << 2 * (n - 1) - maxDepth << endl;
    
    return 0;
}
import java.util.*;

public class Main {
    static int maxDepth = 0;  // 记录最远叶子节点的深度
    
    static void dfs(List<List<Integer>> graph, boolean[] visited, int curr, int depth) {
        visited[curr] = true;
        
        boolean isLeaf = true;
        for(int next : graph.get(curr)) {
            if(!visited[next]) {
                isLeaf = false;
                dfs(graph, visited, next, depth + 1);
            }
        }
        
        if(isLeaf) {
            maxDepth = Math.max(maxDepth, depth);
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        // 构建邻接表
        List<List<Integer>> graph = new ArrayList<>();
        for(int i = 0; i <= n; i++) {
            graph.add(new ArrayList<>());
        }
        
        for(int i = 0; i < n - 1; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            graph.get(x).add(y);
            graph.get(y).add(x);
        }
        
        // DFS找最远叶子节点
        boolean[] visited = new boolean[n + 1];
        dfs(graph, visited, 1, 0);
        
        // 计算结果
        System.out.println(2 * (n - 1) - maxDepth);
    }
}

from collections import deque

def bfs(graph, start, n):
    visited = [False] * (n + 1)
    depth = [0] * (n + 1)
    queue = deque([(start, 0)])  # (节点, 深度)
    visited[start] = True
    max_depth = 0
    
    while queue:
        curr, d = queue.popleft()
        max_depth = max(max_depth, d)
        
        for next_node in graph[curr]:
            if not visited[next_node]:
                visited[next_node] = True
                depth[next_node] = d + 1
                queue.append((next_node, d + 1))
    
    return max_depth

def solve():
    n = int(input())
    
    # 构建邻接表
    graph = [[] for _ in range(n + 1)]
    for _ in range(n - 1):
        x, y = map(int, input().split())
        graph[x].append(y)
        graph[y].append(x)
    
    # BFS找最远节点
    max_depth = bfs(graph, 1, n)
    
    # 计算结果
    print(2 * (n - 1) - max_depth)

if __name__ == "__main__":
    solve()


算法及复杂度

  • 算法:DFS
  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n),其中 n n n是节点数
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n),用于存储图和访问数组

题目链接

回文素数

题目难度:中等

知识点:数学逻辑,数组

解题思路:首先判断数字是否为回文,然后判断数字是否为素数,若都是,则为回文素数。下面具体介绍回文和素数的判断方法。

方法一

回文的判断方法:对数字取余得到个位数字,然后对该数字除以十后取余,得到十位上的数字,随后继续除以十后取余获得百位上的数字,直至数字为0时停止。将各个位上的倒着排列组成新的数字,判断新数字是否与原来的数字相等,若相等,则为回文。
素数的判断方法:若待判断数字为n,由2至n-1共进行n-2次循环,判断该数字是否能被n整除,若能则不是素数,若都不能,则是素数。

import java.io.*;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        String[] s=bf.readLine().split(" ");
        int l=Integer.parseInt(s[0]);
        int r=Integer.parseInt(s[1]);
        int count=0;
        //循环判断[L, R]区间内的每一个数字是否为即为回文又为素数
        for(int i=l;i&lt;=r;i++) {
            if(isPalindrome(i)&amp;&amp;isprime(i))
                count++;
            else
                continue;
        }
        System.out.println(count);
    }
    //判断一个数是否为素数
    public static boolean isprime(int n) {
    	if(n==1) {
    		return false;
    	}
        for(int i=2;i&lt;n;i++){
            if(n%i==0) {
                return false;
            }
        }
        return true;
    }
    //判断一个数是否为回文
    public static boolean isPalindrome(int n) {
        int k=n;int num=0;
        while(k!=0) {
            num=num*10+k%10;
            k=k/10;
        }
        return num==n;
    }
}

方法二

回文的判断方法:将数字转换为字符串,用两个下标start和end分别标记字符串的第一个字符和最后一个字符,使字符串中字符分别从由前往后和从由后往前访问,若前后访问过程中字符均相等,则为回文,否则不是,循环结束条件为start<end。
素数的判断方法:如果一个数不是素数,那它就可以写成是两个数字的乘积,而其中较小的一个数字必然小于等于该数的平方根,因此,在循环判断中,只判断2到该数的平方根之间的数能否被整除即可。

import java.io.*;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        String[] s=bf.readLine().split(" ");
        int l=Integer.parseInt(s[0]);
        int r=Integer.parseInt(s[1]);
        int count=0;
        //循环判断[L, R]区间内的每一个数字是否为即为回文又为素数
        for(int i=l;i&lt;=r;i++) {
            if(isPalindrome(i)&amp;&amp;isprime(i))
                count++;
            else
                continue;
        }
        System.out.println(count);
    }
    //判断一个数是否为素数
    public static boolean isprime(int n) {
    	if(n==1) {
    		return false;
    	}
        if (n==2){
            return true;
        }
        for(int i=2;i&lt;Math.sqrt(n)+1;i++){
            if(n%i==0) {
                return false;
            }
        }
        return true;
    }
    //判断一个数是否为回文
    public static boolean isPalindrome(int n){
        String s=String.valueOf(n);
        int start=0,end=s.length()-1;
        while(start&lt;end){
        if(s.charAt(start)!=s.charAt(end)){
            return false;
        }
            start++;
            end--;
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值