校招算法笔面试 | 校招笔面试真题-序列合并

题目## 题目

题目链接

解题思路

这是一道关于多项式序列的题目。主要思路如下:

  1. 问题分析:

    • 给定 k k k 个7次多项式,每个多项式只有两个非零系数
    • 需要找到所有序列中第 n n n 小的数字
    • 每个序列是将 n = 1 , 2 , 3... n=1,2,3... n=1,2,3... 代入多项式得到的值
  2. 优化思路:

    • 使用优先队列维护 k k k 个序列的当前最小值
    • 每次取出最小值后,将同一序列的下一个值加入队列
    • 使用霍纳法则(Horner’s method)优化多项式计算
  3. 关键点:

    • 使用小根堆维护当前最小值
    • 记录每个序列的下一个位置
    • 高效计算多项式值

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 8;

struct Node {
    long value;
    int id;
};

struct cmp {
    bool operator()(const Node &a, const Node &b) {
        return a.value > b.value;
    }
};

// 使用霍纳法则计算多项式值
int compute(vector<int> &seq, int n) {
    long ret = seq[0];
    for(int i = 1; i < N; i++) {
        ret = ret * n + seq[i];
    }
    return ret;
}

int main() {
    int k = 0, n = 0;
    scanf("%d", &k);
    vector<vector<int>> seq(k, vector<int>(N, 0));
    
    // 读入k个多项式的系数
    for(int i = 0; i < k; i++) {
        for(int j = 0; j < N; j++) {
            scanf("%d", &seq[i][j]);
        }
    }
    scanf("%d", &n);
    
    // 初始化优先队列和每个序列的下一个位置
    priority_queue<Node, vector<Node>, cmp> q;
    vector<int> next(k, 1);
    long val = 0;
    
    // 将每个序列的第一个值加入队列
    for(int i = 0; i < k; i++) {
        val = compute(seq[i], next[i]);
        q.push({val, i});
        ++next[i];
    }
    
    // 找第n小的数
    while(--n) {
        Node cur = q.top(); q.pop();
        val = compute(seq[cur.id], next[cur.id]);
        q.push({val, cur.id});
        ++next[cur.id];
    }
    
    cout << q.top().value << endl;
    return 0;
}
import java.util.*;

public class Main {
    static class Node {
        long value;
        int id;
        
        Node(long value, int id) {
            this.value = value;
            this.id = id;
        }
    }
    
    static long compute(int[] seq, int n) {
        long ret = seq[0];
        for(int i = 1; i < 8; i++) {
            ret = ret * n + seq[i];
        }
        return ret;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int k = sc.nextInt();
        int[][] seq = new int[k][8];
        
        for(int i = 0; i < k; i++) {
            for(int j = 0; j < 8; j++) {
                seq[i][j] = sc.nextInt();
            }
        }
        int n = sc.nextInt();
        
        PriorityQueue<Node> pq = new PriorityQueue<>((a, b) -> 
            Long.compare(a.value, b.value));
        int[] next = new int[k];
        Arrays.fill(next, 1);
        
        for(int i = 0; i < k; i++) {
            long val = compute(seq[i], next[i]);
            pq.offer(new Node(val, i));
            next[i]++;
        }
        
        while(--n > 0) {
            Node cur = pq.poll();
            long val = compute(seq[cur.id], next[cur.id]);
            pq.offer(new Node(val, cur.id));
            next[cur.id]++;
        }
        
        System.out.println(pq.peek().value);
    }
}
from heapq import heappush, heappop

def compute(seq, n):
    ret = seq[0]
    for i in range(1, 8):
        ret = ret * n + seq[i]
    return ret

k = int(input())
seq = []
for _ in range(k):
    seq.append(list(map(int, input().split())))
n = int(input())

# 使用堆来维护最小值
heap = []
next_pos = [1] * k

# 初始化堆
for i in range(k):
    val = compute(seq[i], next_pos[i])
    heappush(heap, (val, i))
    next_pos[i] += 1

# 找第n小的数
for _ in range(n-1):
    val, idx = heappop(heap)
    new_val = compute(seq[idx], next_pos[idx])
    heappush(heap, (new_val, idx))
    next_pos[idx] += 1

print(heap[0][0])

算法分析

  • 时间复杂度: O ( n log ⁡ k ) \mathcal{O}(n\log k) O(nlogk)
    • 每次操作堆的时间为 log ⁡ k \log k logk
    • 需要进行 n n n 次操作
  • 空间复杂度: O ( k ) \mathcal{O}(k) O(k)
    • 优先队列存储 k k k 个元素
    • 存储 k k k 个序列的下一个位置

题目链接

解题思路

这是一道分班问题,主要思路如下:

  1. 问题分析:

    • 一个大班要分成两个小班
    • 每个小朋友可能不希望和某些人同班
    • 需要判断是否能满足所有要求
    • 本质是一个二分图染色问题
  2. 解决方案:

    • 使用两个数组记录每个小朋友的分班情况
    • 对于每个请求 ( a , b ) (a,b) (a,b),尝试将 a , b a,b a,b 分到不同班
    • 如果发现冲突,则无法满足要求
    • 贪心策略:遇到新的请求就立即分班
  3. 实现细节:

    • 使用数组标记每个小朋友在不同班级的状态
    • 0表示未分配,1表示不能在该班
    • 处理每对不想同班的请求

代码

#include <iostream>
using namespace std;

int main() {
    int first[10000] = {0}, second[10000] = {0};
    int m, n;  // m为总人数,n为请求数
    
    cin >> m >> n;
    for(int i = 0; i < n; i++) {
        int a, b;
        cin >> a >> b;
        
        // 尝试将a分到第一班,b分到第二班
        if(first[a] == 0 && second[b] == 0) {
            first[b] = 1;  // b不能进第一班
            second[a] = 1;  // a不能进第二班
        }
        // 尝试将a分到第二班,b分到第一班
        else if(first[b] == 0 && second[a] == 0) {
            first[a] = 1;
            second[b] = 1;
        }
        else {
            cout << "0" << endl;  // 无法满足要求
            return 0;
        }
    }
    
    cout << "1" << endl;  // 可以满足所有要求
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[] first = new int[10000];
        int[] second = new int[10000];
        
        int m = sc.nextInt();  // 总人数
        int n = sc.nextInt();  // 请求数
        
        for(int i = 0; i < n; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            
            // 尝试将a分到第一班,b分到第二班
            if(first[a] == 0 && second[b] == 0) {
                first[b] = 1;  // b不能进第一班
                second[a] = 1;  // a不能进第二班
            }
            // 尝试将a分到第二班,b分到第一班
            else if(first[b] == 0 && second[a] == 0) {
                first[a] = 1;
                second[b] = 1;
            }
            else {
                System.out.println("0");  // 无法满足要求
                return;
            }
        }
        
        System.out.println("1");  // 可以满足所有要求
        sc.close();
    }
}
def can_satisfy_requests(m: int, requests: list) -> bool:
    first = [0] * 10000
    second = [0] * 10000
    
    for a, b in requests:
        # 尝试将a分到第一班,b分到第二班
        if first[a] == 0 and second[b] == 0:
            first[b] = 1  # b不能进第一班
            second[a] = 1  # a不能进第二班
        # 尝试将a分到第二班,b分到第一班
        elif first[b] == 0 and second[a] == 0:
            first[a] = 1
            second[b] = 1
        else:
            return False
    return True

def main():
    m = int(input())
    n = int(input())
    requests = []
    for _ in range(n):
        a, b = map(int, input().split())
        requests.append((a, b))
    
    print("1" if can_satisfy_requests(m, requests) else "0")

if __name__ == "__main__":
    main()

算法及复杂度

  • 算法:贪心
  • 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - n n n 为请求数量
  • 空间复杂度: O ( m ) \mathcal{O}(m) O(m) - m m m 为总人数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值