校招算法笔面试 | 校招笔面试真题-平均值

题目## 题目

题目链接

题目链接

平均值

题目描述

给出两个正整数 x 和 y,每次可以选择其中一个数字,然后将其替换为 x 和 y 的几何平均数或者平方平均数。问最少经过几次替换,可以使得两个数相等。

注:

  • 几何平均数: ⌈ x ⋅ y ⌉ \lceil \sqrt{x \cdot y} \rceil xy (向上取整)
  • 平方平均数: ⌊ x 2 + y 2 2 ⌋ \lfloor \sqrt{\frac{x^2 + y^2}{2}} \rfloor 2x2+y2 (向下取整)

输入:

  • 一行两个正整数 x 和 y

输出:

  • 输出一个非负整数,表示最少的替换次数

解题思路

这是一个搜索问题,可以通过以下步骤解决:

  1. 关键发现:

    • 每次可以选择两种平均数中的一种
    • 可以选择替换任意一个数
    • 需要找到最少的替换次数
  2. 解题策略:

    • 使用BFS搜索所有可能的状态
    • 记录已访问的状态避免重复
    • 当两数相等时返回步数
  3. 具体步骤:

    • 使用队列存储状态和步数
    • 对每个状态尝试所有可能的操作
    • 记录已访问状态避免循环
    • 找到最短路径

代码

#include <bits/stdc++.h>
using namespace std;

struct State {
    int x, y, steps;
    State(int _x, int _y, int _s): x(_x), y(_y), steps(_s) {}
};

int main() {
    int x, y;
    cin >> x >> y;
    
    if(x == y) {
        cout << 0 << endl;
        return 0;
    }
    
    queue<State> q;
    set<pair<int,int>> visited;
    
    q.push(State(x, y, 0));
    visited.insert({x, y});
    
    while(!q.empty()) {
        State curr = q.front();
        q.pop();
        
        // 计算两种平均数
        int geo = ceil(sqrt(1.0 * curr.x * curr.y));
        int sqr = floor(sqrt((1.0 * curr.x * curr.x + curr.y * curr.y) / 2));
        
        // 尝试替换x
        if(!visited.count({geo, curr.y})) {
            if(geo == curr.y) return cout << curr.steps + 1 << endl, 0;
            q.push(State(geo, curr.y, curr.steps + 1));
            visited.insert({geo, curr.y});
        }
        if(!visited.count({sqr, curr.y})) {
            if(sqr == curr.y) return cout << curr.steps + 1 << endl, 0;
            q.push(State(sqr, curr.y, curr.steps + 1));
            visited.insert({sqr, curr.y});
        }
        
        // 尝试替换y
        if(!visited.count({curr.x, geo})) {
            if(geo == curr.x) return cout << curr.steps + 1 << endl, 0;
            q.push(State(curr.x, geo, curr.steps + 1));
            visited.insert({curr.x, geo});
        }
        if(!visited.count({curr.x, sqr})) {
            if(sqr == curr.x) return cout << curr.steps + 1 << endl, 0;
            q.push(State(curr.x, sqr, curr.steps + 1));
            visited.insert({curr.x, sqr});
        }
    }
    
    return 0;
}
import java.util.*;

public class Main {
    static class State {
        int x, y, steps;
        State(int x, int y, int steps) {
            this.x = x;
            this.y = y;
            this.steps = steps;
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int y = sc.nextInt();
        
        if(x == y) {
            System.out.println(0);
            return;
        }
        
        Queue<State> q = new LinkedList<>();
        Set<String> visited = new HashSet<>();
        
        q.offer(new State(x, y, 0));
        visited.add(x + "," + y);
        
        while(!q.isEmpty()) {
            State curr = q.poll();
            
            // 计算两种平均数
            int geo = (int)Math.ceil(Math.sqrt(1.0 * curr.x * curr.y));
            int sqr = (int)Math.floor(Math.sqrt((1.0 * curr.x * curr.x + curr.y * curr.y) / 2));
            
            // 尝试替换x
            String key = geo + "," + curr.y;
            if(!visited.contains(key)) {
                if(geo == curr.y) {
                    System.out.println(curr.steps + 1);
                    return;
                }
                q.offer(new State(geo, curr.y, curr.steps + 1));
                visited.add(key);
            }
            key = sqr + "," + curr.y;
            if(!visited.contains(key)) {
                if(sqr == curr.y) {
                    System.out.println(curr.steps + 1);
                    return;
                }
                q.offer(new State(sqr, curr.y, curr.steps + 1));
                visited.add(key);
            }
            
            // 尝试替换y
            key = curr.x + "," + geo;
            if(!visited.contains(key)) {
                if(geo == curr.x) {
                    System.out.println(curr.steps + 1);
                    return;
                }
                q.offer(new State(curr.x, geo, curr.steps + 1));
                visited.add(key);
            }
            key = curr.x + "," + sqr;
            if(!visited.contains(key)) {
                if(sqr == curr.x) {
                    System.out.println(curr.steps + 1);
                    return;
                }
                q.offer(new State(curr.x, sqr, curr.steps + 1));
                visited.add(key);
            }
        }
    }
}
from collections import deque
import math

def solve(x, y):
    if x == y:
        return 0
    
    q = deque([(x, y, 0)])  # (x, y, steps)
    visited = {(x, y)}
    
    while q:
        curr_x, curr_y, steps = q.popleft()
        
        # 计算两种平均数
        geo = math.ceil(math.sqrt(curr_x * curr_y))
        sqr = math.floor(math.sqrt((curr_x * curr_x + curr_y * curr_y) / 2))
        
        # 尝试替换x
        if (geo, curr_y) not in visited:
            if geo == curr_y:
                return steps + 1
            q.append((geo, curr_y, steps + 1))
            visited.add((geo, curr_y))
        if (sqr, curr_y) not in visited:
            if sqr == curr_y:
                return steps + 1
            q.append((sqr, curr_y, steps + 1))
            visited.add((sqr, curr_y))
        
        # 尝试替换y
        if (curr_x, geo) not in visited:
            if geo == curr_x:
                return steps + 1
            q.append((curr_x, geo, steps + 1))
            visited.add((curr_x, geo))
        if (curr_x, sqr) not in visited:
            if sqr == curr_x:
                return steps + 1
            q.append((curr_x, sqr, steps + 1))
            visited.add((curr_x, sqr))

x, y = map(int, input().split())
print(solve(x, y))

算法及复杂度

  • 算法:BFS(广度优先搜索)
  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - n 是可能的状态数,与输入数值大小相关
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要存储已访问的状态

注意:

  1. 需要使用浮点数计算平均数,避免整数除法的误差
  2. 注意向上取整和向下取整的处理
  3. 使用visited集合避免重复访问相同状态
  4. 当找到相等的数时立即返回结果

题目链接

解题思路

  1. 基本思路:

    • 使用拓扑排序算法对DAG进行排序,同时考虑节点的权重。
    • 在拓扑排序过程中,优先选择权重大的节点进行排序。
  2. 实现方法:

    • 使用Kahn算法进行拓扑排序。
    • 使用优先队列(最大堆)来确保每次选择权重最大的节点。

代码

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

int main() {
    int n, e;
    cin >> n >> e;

    vector<int> weights(n + 1);
    vector<vector<int>> graph(n + 1);
    vector<int> in_degree(n + 1, 0);

    // 读取节点的权重
    for (int i = 1; i <= n; i++) {
        int seq, weight;
        cin >> seq >> weight;
        weights[seq] = weight;
    }

    // 读取边的信息
    for (int i = 0; i < e; i++) {
        int s, t;
        cin >> s >> t;
        graph[s].push_back(t);
        in_degree[t]++;
    }

    // 使用优先队列进行拓扑排序
    priority_queue<pair<int, int>> pq; // (weight, node)
    for (int i = 1; i <= n; i++) {
        if (in_degree[i] == 0) {
            pq.push({weights[i], i});
        }
    }

    vector<int> result;
    while (!pq.empty()) {
        int node = pq.top().second;
        pq.pop();
        result.push_back(node);

        for (int neighbor : graph[node]) {
            in_degree[neighbor]--;
            if (in_degree[neighbor] == 0) {
                pq.push({weights[neighbor], neighbor});
            }
        }
    }

    // 输出结果
    for (int i = 0; i < result.size(); i++) {
        cout << result[i];
        if (i < result.size() - 1) {
            cout << " ";
        }
    }
    cout << endl;

    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int e = sc.nextInt();

        int[] weights = new int[n + 1];
        List<List<Integer>> graph = new ArrayList<>(n + 1);
        int[] inDegree = new int[n + 1];

        for (int i = 0; i <= n; i++) {
            graph.add(new ArrayList<>());
        }

        // 读取节点的权重
        for (int i = 1; i <= n; i++) {
            int seq = sc.nextInt();
            int weight = sc.nextInt();
            weights[seq] = weight;
        }

        // 读取边的信息
        for (int i = 0; i < e; i++) {
            int s = sc.nextInt();
            int t = sc.nextInt();
            graph.get(s).add(t);
            inDegree[t]++;
        }

        // 使用优先队列进行拓扑排序
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[0] - a[0]); // (weight, node)
        for (int i = 1; i <= n; i++) {
            if (inDegree[i] == 0) {
                pq.offer(new int[]{weights[i], i});
            }
        }

        List<Integer> result = new ArrayList<>();
        while (!pq.isEmpty()) {
            int node = pq.poll()[1];
            result.add(node);

            for (int neighbor : graph.get(node)) {
                inDegree[neighbor]--;
                if (inDegree[neighbor] == 0) {
                    pq.offer(new int[]{weights[neighbor], neighbor});
                }
            }
        }

        // 输出结果
        for (int i = 0; i < result.size(); i++) {
            System.out.print(result.get(i));
            if (i < result.size() - 1) {
                System.out.print(" ");
            }
        }
        System.out.println();
    }
}
import heapq

def topological_sort(n, e, weights, edges):
    graph = [[] for _ in range(n + 1)]
    in_degree = [0] * (n + 1)

    # 构建图和入度数组
    for s, t in edges:
        graph[s].append(t)
        in_degree[t] += 1

    # 使用优先队列进行拓扑排序
    pq = []
    for i in range(1, n + 1):
        if in_degree[i] == 0:
            heapq.heappush(pq, (-weights[i], i))  # 使用负值以实现最大堆

    result = []
    while pq:
        weight, node = heapq.heappop(pq)
        result.append(node)

        for neighbor in graph[node]:
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                heapq.heappush(pq, (-weights[neighbor], neighbor))

    return result

if __name__ == "__main__":
    n, e = map(int, input().split())
    weights = [0] * (n + 1)
    for _ in range(n):
        seq, weight = map(int, input().split())
        weights[seq] = weight

    edges = [tuple(map(int, input().split())) for _ in range(e)]
    result = topological_sort(n, e, weights, edges)

    print(" ".join(map(str, result)))

算法及复杂度

  • 算法:拓扑排序
  • 时间复杂度: O ( n + e ) \mathcal{O}(n + e) O(n+e),其中 n n n 为节点数, e e e 为边数
  • 空间复杂度: O ( n + e ) \mathcal{O}(n + e) O(n+e),用于存储图和入度数组
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值