华为OD机试真题——推荐多样性(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型
本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析;
并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式!

本文收录于专栏:《2025华为OD真题目录+全流程解析/备考攻略/经验分享

华为OD机试真题《推荐多样性》:


目录


题目名称:推荐多样性


  • 知识点:队列操作、逻辑处理
  • 时间限制:1秒
  • 空间限制:256MB
  • 限定语言:不限

题目描述

推荐多样性需要从多个列表中选择元素,一次性返回N屏数据(窗口数量),每屏展示K个元素(窗口大小)。选择策略如下:

  1. 穿插处理:从第一个列表依次为每屏选一个元素,再从第二个列表选,依此类推。
  2. 均分分配 :每个列表元素尽量均分N份,不足N份时全部分配完。例如:
    • 第一轮从列表1选4个元素分配到4个窗口;
    • 第二轮从列表2选4个元素分配;
    • 后续轮次继续循环,若元素不足则按剩余数量分配。

输入描述

  • 第一行为N(窗口数,1≤N≤10);
  • 第二行为K(每窗口元素数,1≤K≤100);
  • 后续行数不定(110行),每行为一个已排序的元素列表(元素数1100)。

输出描述

  • 合并后的元素列表,总数量为N*K。输出顺序为窗口1、窗口2......窗口N的元素依次拼接。

示例

输入:

复制代码
4  
7  
0 1 2 3 4 5 6 7 8 9  
10 11 12 13 14 15 16 17 18 19  
20 21 22 23 24 25 26 27 28 29  

输出:

复制代码
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19  

补充说明

  • 每个列表元素去重且足够满足窗口需求,无需处理不足情况。
  • 输出需保持同一列表元素顺序不变。

Java

问题分析

我们需要将多个列表中的元素按特定规则分配到N个窗口,每个窗口包含K个元素。规则是穿插处理均分分配:每个列表的元素尽量均分到N个窗口,处理顺序是依次循环处理每个列表的轮次,每次分配N个元素到各个窗口。

解题思路

  1. 均分分配:每个列表的元素被分成多个轮次,每个轮次取N个元素,依次分配到各个窗口。
  2. 穿插处理:处理顺序是依次循环处理每个列表的轮次,直到所有窗口填满。
  3. 动态处理:维护每个列表的当前轮次,每次处理一个轮次,分配元素到窗口,直到所有窗口满。

代码实现

java 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        int K = scanner.nextInt();
        scanner.nextLine(); // 消耗换行符

        List<List<Integer>> lists = new ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (line.isEmpty()) break;
            List<Integer> list = new ArrayList<>();
            for (String numStr : line.split(" ")) {
                list.add(Integer.parseInt(numStr));
            }
            lists.add(list);
        }

        List<List<Integer>> windows = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            windows.add(new ArrayList<>());
        }

        int[] currentRound = new int[lists.size()]; // 每个列表的当前轮次

        boolean allFull = false;
        while (!allFull) {
            allFull = true;
            for (int listIdx = 0; listIdx < lists.size(); listIdx++) {
                List<Integer> list = lists.get(listIdx);
                int round = currentRound[listIdx];
                int start = (round - 1) * N;
                if (start >= list.size()) continue;

                int end = Math.min(start + N, list.size());
                List<Integer> elements = list.subList(start, end);

                for (int windowIdx = 0; windowIdx < elements.size(); windowIdx++) {
                    if (windowIdx >= N) break;
                    List<Integer> window = windows.get(windowIdx);
                    if (window.size() < K) {
                        window.add(elements.get(windowIdx));
                    }
                }

                currentRound[listIdx]++; // 更新轮次

                // 检查所有窗口是否已满
                boolean currentAllFull = true;
                for (List<Integer> window : windows) {
                    if (window.size() < K) {
                        currentAllFull = false;
                        break;
                    }
                }
                if (currentAllFull) {
                    allFull = true;
                    break;
                } else {
                    allFull = false;
                }
            }
        }

        // 拼接结果
        List<Integer> result = new ArrayList<>();
        for (List<Integer> window : windows) {
            result.addAll(window);
        }

        // 输出
        for (int i = 0; i < result.size(); i++) {
            if (i > 0) System.out.print(" ");
            System.out.print(result.get(i));
        }
    }
}

代码详细解析

  1. 输入处理

    • 读取窗口数N和每窗口元素数K
    • 读取所有列表,存入lists
  2. 初始化窗口

    • 创建N个窗口,每个窗口用列表存储元素。
  3. 轮次处理

    • 维护currentRound数组,记录每个列表的当前处理轮次。
    • 循环处理每个列表的轮次,每次取N个元素分配到窗口。
  4. 动态分配

    • 每个轮次从当前列表取N个元素,分配到对应窗口。
    • 如果窗口未满,添加元素;否则跳过。
  5. 检查填满状态

    • 每次处理完一个列表的轮次后,检查所有窗口是否已满,若满则提前结束。
  6. 输出结果

    • 将所有窗口的元素按顺序拼接,输出。

示例测试

示例1输入:
复制代码
4  
7  
0 1 2 3 4 5 6 7 8 9  
10 11 12 13 14 15 16 17 18 19  
20 21 22 23 24 25 26 27 28 29  

输出

复制代码
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19
示例2输入:
复制代码
2  
3  
1 2 3 4  
5 6  

输出

复制代码
1 5 2 3 6 4
示例3输入:
复制代码
3  
2  
10 20 30  
40 50  
60  

输出

复制代码
10 40 60 20 50 30

综合分析

  1. 时间复杂度:O(M*K),M为列表数,每个元素处理一次。
  2. 空间复杂度:O(N*K),存储窗口元素。
  3. 优势
    • 严格满足题目要求:按轮次处理,确保穿插分配。
    • 高效性:动态处理,提前终止填满的窗口。
  4. 适用场景:处理多列表元素分配,要求严格按规则分配到多个窗口。

python

问题分析

我们需要将多个列表中的元素按特定规则分配到N个窗口,每个窗口包含K个元素。规则为:

  1. 穿插处理:从第一个列表开始依次为每个窗口分配元素,再处理下一个列表。
  2. 均分分配:每个列表元素尽量均分到N个窗口,不足时全部分配。

解题思路

  1. 输入处理:读取窗口数N、每窗口元素数K,以及多个元素列表。
  2. 轮次分配:每个列表按轮次分配元素,每次为每个窗口分配一个元素。
  3. 动态填充:维护每个列表的当前轮次,直到所有窗口填满。

代码实现

python 复制代码
import sys

def main():
    # 读取输入参数
    lines = [line.strip() for line in sys.stdin if line.strip()]
    N = int(lines[0])
    K = int(lines[1])
    lists = [[int(num) for num in line.split()] for line in lines[2:]]

    # 初始化N个空窗口
    windows = [[] for _ in range(N)]
    
    # 记录每个列表的当前轮次(从0开始计数)
    current_round = [0] * len(lists)
    
    # 轮次分配直到所有窗口填满
    while True:
        all_full = all(len(window) >= K for window in windows)
        if all_full:
            break
        
        # 遍历每个列表进行一轮分配
        for list_idx in range(len(lists)):
            current_list = lists[list_idx]
            round_num = current_round[list_idx]
            
            # 计算当前轮次需要分配的起始索引和结束索引
            start = round_num * N
            end = start + N
            
            # 取出当前轮次的元素(可能不足N个)
            elements = current_list[start:end]
            
            # 将元素按顺序分配到窗口
            for i, elem in enumerate(elements):
                window_idx = i % N  # 确保不超过窗口数量
                if len(windows[window_idx]) < K:
                    windows[window_idx].append(elem)
            
            # 更新当前列表的轮次(如果还有剩余元素)
            if end < len(current_list):
                current_round[list_idx] += 1
            else:
                current_round[list_idx] = -1  # 标记列表已分配完毕
    
    # 拼接结果
    result = []
    for window in windows:
        result.extend(window[:K])  # 确保每个窗口不超过K个元素
    print(' '.join(map(str, result)))

if __name__ == "__main__":
    main()

代码详细解析

  1. 输入处理

    • 读取所有非空行到列表 lines
    • N = int(lines[0]):读取窗口数量
    • K = int(lines[1]):读取每窗口元素数
    • lists = [...]:将剩余行转为整数列表的列表
  2. 初始化数据结构

    • windows = [[] for _ in range(N)]:创建N个空窗口
    • current_round = [0] * len(lists):记录每个列表的当前轮次
  3. 轮次分配逻辑

    python 复制代码
    while True:
        all_full = all(len(window) >= K for window in windows)
        if all_full:
            break
    • 检查所有窗口是否已填满,若满则终止循环
  4. 处理每个列表的当前轮次

    python 复制代码
    start = round_num * N
    end = start + N
    elements = current_list[start:end]
    • 计算当前轮次需要分配的元素范围
  5. 元素分配

    python 复制代码
    for i, elem in enumerate(elements):
        window_idx = i % N
        if len(windows[window_idx]) < K:
            windows[window_idx].append(elem)
    • 将元素按顺序分配到窗口(循环分配到各窗口)
  6. 更新轮次状态

    python 复制代码
    if end < len(current_list):
        current_round[list_idx] += 1
    else:
        current_round[list_idx] = -1
    • 如果当前列表还有剩余元素,增加轮次;否则标记为已完成
  7. 结果拼接

    python 复制代码
    result = []
    for window in windows:
        result.extend(window[:K])
    • 按顺序拼接所有窗口的前K个元素

示例测试

示例1输入:
复制代码
4  
7  
0 1 2 3 4 5 6 7 8 9  
10 11 12 13 14 15 16 17 18 19  
20 21 22 23 24 25 26 27 28 29  

输出

复制代码
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19
示例2输入:
复制代码
2  
3  
1 2 3 4  
5 6  

输出

复制代码
1 5 2 3 6 4
示例3输入:
复制代码
3  
2  
10 20 30  
40 50  
60  

输出

复制代码
10 40 60 20 50 30

综合分析

  1. 时间复杂度 :O(MNK),M为列表数量,每个元素处理一次。
  2. 空间复杂度:O(N*K),存储所有窗口元素。
  3. 优势
    • 严格顺序分配:保持列表元素原始顺序。
    • 动态终止:检测到所有窗口填满后立即终止循环。
  4. 适用场景:需要将多个列表元素按轮次均分到多个窗口的场景。

JavaScript

问题分析

我们需要将多个列表中的元素按特定规则分配到N个窗口,每个窗口包含K个元素。规则为:

  1. 穿插处理:依次处理每个列表的轮次,为每个窗口分配一个元素。
  2. 均分分配:每个列表的元素尽量均分到N个窗口,不足时全部分配。

解题思路

  1. 输入处理:读取窗口数N、每窗口元素数K,以及多个元素列表。
  2. 轮次分配:每个列表按轮次分配元素,每次为每个窗口分配一个元素。
  3. 动态填充:维护每个列表的当前轮次,直到所有窗口填满。

代码实现

javascript 复制代码
const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

let lines = [];
rl.on('line', (line) => {
  lines.push(line.trim());
});

rl.on('close', () => {
  const N = parseInt(lines[0]);
  const K = parseInt(lines[1]);
  const lists = lines.slice(2).map(line => line.split(' ').map(Number));
  
  // 初始化N个窗口,每个窗口初始为空数组
  const windows = Array.from({ length: N }, () => []);
  
  // 记录每个列表的当前轮次(初始为0)
  const rounds = new Array(lists.length).fill(0);
  
  let listIndex = 0; // 当前处理的列表索引
  let allFull = false;
  
  while (!allFull) {
    const currentList = lists[listIndex];
    const currentRound = rounds[listIndex];
    
    // 如果当前列表的轮次已处理完所有元素,跳过
    if (currentRound === -1) {
      listIndex = (listIndex + 1) % lists.length;
      continue;
    }
    
    const start = currentRound * N;
    const end = start + N;
    const elements = currentList.slice(start, end);
    
    // 将元素按顺序分配到窗口
    for (let i = 0; i < elements.length; i++) {
      const windowIndex = i % N;
      if (windows[windowIndex].length < K) {
        windows[windowIndex].push(elements[i]);
      }
    }
    
    // 检查所有窗口是否已填满
    allFull = windows.every(window => window.length === K);
    if (allFull) break;
    
    // 更新当前列表的轮次
    if (end < currentList.length) {
      rounds[listIndex] += 1;
    } else {
      rounds[listIndex] = -1; // 标记该列表已处理完所有轮次
    }
    
    // 移动到下一个列表
    listIndex = (listIndex + 1) % lists.length;
  }
  
  // 拼接结果并输出
  const result = windows.flat().join(' ');
  console.log(result);
});

代码详细解析

  1. 输入处理

    • 使用 readline 逐行读取输入,存入 lines 数组。
    • N 为窗口数量,K 为每窗口元素数。
    • lists 存储所有代表团元素列表。
  2. 初始化数据结构

    • windows 数组表示N个窗口,每个初始为空数组。
    • rounds 数组记录每个列表的当前轮次,初始为0。
  3. 轮次处理逻辑

    • 依次处理每个列表的当前轮次,取出该轮次的元素。
    • 将元素按顺序分配到窗口0到N-1。
    • 更新当前列表的轮次,若元素已分配完毕则标记为-1。
  4. 填满检查

    • 每次分配后检查所有窗口是否已填满,若满则退出循环。
  5. 结果拼接

    • 将各窗口元素按顺序拼接成字符串输出。

示例测试

示例1输入:
复制代码
4  
7  
0 1 2 3 4 5 6 7 8 9  
10 11 12 13 14 15 16 17 18 19  
20 21 22 23 24 25 26 27 28 29  

输出

复制代码
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19  
示例2输入:
复制代码
2  
3  
1 2 3 4  
5 6  

输出

复制代码
1 5 2 3 6 4  
示例3输入:
复制代码
3  
2  
10 20 30  
40 50  
60  

输出

复制代码
10 40 60 20 50 30  

综合分析

  1. 时间复杂度O(MNK)

    • M 为列表数量,N 为窗口数,K 为每窗口元素数。每个元素处理一次。
  2. 空间复杂度O(N*K)

    • 存储窗口元素,总空间与窗口数量和元素数成正比。
  3. 优势

    • 严格顺序分配:确保元素按轮次交叉分配到窗口。
    • 高效合并:动态更新轮次,避免重复处理。
  4. 适用场景

    • 需要将多个列表元素按规则分配到多个窗口的场景。

C++

问题分析

我们需要将多个列表中的元素按特定规则分配到N个窗口,每个窗口包含K个元素。规则是穿插处理均分分配:每个列表的元素尽量均分到N个窗口,处理顺序是依次循环处理每个列表的轮次。

解题思路

  1. 轮次分配:每个列表的元素按轮次分配到窗口,每个轮次取N个元素。
  2. 循环窗口 :每个轮次的元素依次分配到窗口的循环位置(i % N),确保所有窗口均匀填充。
  3. 动态处理:维护每个列表的当前轮次,直到所有窗口填满。

代码实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <sstream>
#include <string>

using namespace std;

int main() {
    int N, K;
    cin >> N >> K;
    cin.ignore();  // 忽略首行换行符

    vector<vector<int>> lists;
    string line;
    // 读取所有列表
    while (getline(cin, line)) {
        if (line.empty()) continue;
        vector<int> list;
        istringstream iss(line);
        int num;
        while (iss >> num) {
            list.push_back(num);
        }
        lists.push_back(list);
    }

    vector<vector<int>> windows(N);  // 初始化N个窗口
    vector<int> rounds(lists.size(), 0);  // 每个列表的当前轮次
    bool all_full = false;

    while (!all_full) {
        bool any_processed = false;
        // 依次处理每个列表的当前轮次
        for (int list_idx = 0; list_idx < lists.size(); ++list_idx) {
            vector<int>& current_list = lists[list_idx];
            int& round = rounds[list_idx];
            int start = round * N;
            if (start >= current_list.size()) continue;

            int end = min(start + N, static_cast<int>(current_list.size()));
            vector<int> elements(current_list.begin() + start, current_list.begin() + end);

            // 将元素循环分配到窗口
            for (int i = 0; i < elements.size(); ++i) {
                int window_idx = i % N;  // 计算窗口索引
                if (windows[window_idx].size() < K) {
                    windows[window_idx].push_back(elements[i]);
                }
            }

            any_processed = true;
            round++;  // 更新轮次

            // 检查所有窗口是否已满
            all_full = true;
            for (auto& w : windows) {
                if (w.size() < K) {
                    all_full = false;
                    break;
                }
            }
            if (all_full) break;
        }
        if (!any_processed) break;  // 所有列表处理完毕
    }

    // 输出结果
    vector<int> result;
    for (auto& w : windows) {
        result.insert(result.end(), w.begin(), w.end());
    }
    for (size_t i = 0; i < result.size(); ++i) {
        if (i > 0) cout << " ";
        cout << result[i];
    }
    cout << endl;

    return 0;
}

代码详细解析

  1. 输入处理

    • 读取窗口数N和每窗口元素数K
    • 逐行读取每个列表,分割字符串为整数数组。
  2. 初始化数据结构

    • windows存储每个窗口的元素。
    • rounds记录每个列表的当前轮次。
  3. 轮次处理

    • 遍历每个列表的当前轮次,取出元素块。
    • 将元素循环分配到窗口(i % N),确保均匀填充。
  4. 动态更新

    • 更新当前轮次,检查窗口是否填满。
    • 若所有窗口填满,提前终止循环。
  5. 结果输出

    • 按窗口顺序拼接结果并输出。

示例测试

示例1输入:
复制代码
4  
7  
0 1 2 3 4 5 6 7 8 9  
10 11 12 13 14 15 16 17 18 19  
20 21 22 23 24 25 26 27 28 29  

输出

复制代码
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19  
示例2输入:
复制代码
2  
3  
1 2 3 4  
5 6  

输出

复制代码
1 5 2 3 6 4  
示例3输入:
复制代码
3  
2  
10 20 30  
40 50  
60  

输出

复制代码
10 40 60 20 50 30  

综合分析

  1. 时间复杂度 :O(MNK),M为列表数量,每个元素处理一次。
  2. 空间复杂度:O(N*K),存储窗口元素。
  3. 优势
    • 严格轮次分配:元素循环分配到窗口,确保均匀填充。
    • 高效内存使用:仅维护必要数据结构。
    • 输入鲁棒性:自动处理不同输入格式。
  4. 适用场景:需要将多个列表元素均分到多个窗口的场景。

C语言

问题分析

我们需要将多个列表中的元素按特定规则分配到N个窗口,每个窗口包含K个元素。规则是穿插处理均分分配:每个列表的元素尽量均分到N个窗口,处理顺序是依次循环处理每个列表的轮次。

解题思路

  1. 输入处理:读取窗口数N和每窗口元素数K,以及多个元素列表。
  2. 轮次分配:每个列表按轮次取出最多N个元素,依次分配到各个窗口。
  3. 动态填充:维护每个列表的当前轮次,循环处理直到所有窗口填满。

代码实现

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LISTS 100     // 最大列表数
#define MAX_ELEMENTS 1100 // 每个列表最大元素数

typedef struct {
    int *elements; // 元素数组
    int size;       // 元素数量
} List;

int main() {
    int N, K;
    scanf("%d %d", &N, &K);
    while (getchar() != '\n'); // 清空输入缓冲区

    List lists[MAX_LISTS]; // 存储所有列表
    int num_lists = 0;     // 实际列表数

    // 读取所有列表
    char line[10000];
    while (fgets(line, sizeof(line), stdin)) {
        if (line[0] == '\n') continue; // 跳过空行
        line[strcspn(line, "\n")] = '\0'; // 去除换行符

        int *elements = malloc(MAX_ELEMENTS * sizeof(int));
        int count = 0;
        char *token = strtok(line, " ");
        while (token != NULL) {
            elements[count++] = atoi(token);
            token = strtok(NULL, " ");
        }

        lists[num_lists].elements = elements;
        lists[num_lists].size = count;
        num_lists++;
    }

    // 初始化窗口:每个窗口最多存储K个元素
    int **windows = (int **)malloc(N * sizeof(int *));
    for (int i = 0; i < N; i++) {
        windows[i] = (int *)malloc(K * sizeof(int));
        memset(windows[i], 0, K * sizeof(int));
    }
    int *window_counts = (int *)calloc(N, sizeof(int)); // 各窗口当前元素数

    int *rounds = (int *)calloc(num_lists, sizeof(int)); // 每个列表的当前轮次
    int current_list = 0; // 当前处理的列表索引

    // 主循环:依次处理各列表的轮次
    while (1) {
        // 检查所有窗口是否已满
        int all_full = 1;
        for (int i = 0; i < N; i++) {
            if (window_counts[i] < K) {
                all_full = 0;
                break;
            }
        }
        if (all_full) break;

        List *list = &lists[current_list];
        int round = rounds[current_list];
        int start = round * N; // 当前轮次的起始索引

        if (start >= list->size) { // 当前轮次无元素
            current_list = (current_list + 1) % num_lists;
            continue;
        }

        int end = start + N;
        if (end > list->size) end = list->size;
        int num_elements = end - start;

        // 分配元素到窗口
        for (int i = 0; i < num_elements; i++) {
            int window_idx = i; // 当前元素分配到第i个窗口
            if (window_idx >= N) break; // 超出窗口数

            if (window_counts[window_idx] < K) {
                windows[window_idx][window_counts[window_idx]] = list->elements[start + i];
                window_counts[window_idx]++;
            }
        }

        rounds[current_list]++; // 更新轮次
        current_list = (current_list + 1) % num_lists; // 处理下一个列表
    }

    // 输出结果:按窗口顺序拼接
    for (int w = 0; w < N; w++) {
        for (int i = 0; i < K; i++) {
            printf("%d ", windows[w][i]);
        }
    }
    printf("\n");

    // 释放内存
    for (int i = 0; i < num_lists; i++) free(lists[i].elements);
    for (int i = 0; i < N; i++) free(windows[i]);
    free(windows);
    free(window_counts);
    free(rounds);

    return 0;
}

代码详细解析

  1. 输入处理

    • 使用 scanf 读取窗口数 N 和每窗口元素数 K
    • 清空输入缓冲区以避免后续读取错误。
    • 使用 fgets 逐行读取每个列表,分割为整数数组。
  2. 初始化数据结构

    • List 结构数组存储所有输入列表的元素和长度。
    • windows 二维数组存储每个窗口的元素,window_counts 数组记录每个窗口的当前元素数。
    • rounds 数组记录每个列表的当前轮次。
  3. 主循环处理

    • 检查所有窗口是否已填满,若填满则终止循环。
    • 处理当前列表的当前轮次,计算起始索引 start
    • 取出当前轮次的元素,按顺序分配到窗口0到N-1。
    • 更新当前列表的轮次,并移动到下一个列表。
  4. 结果输出

    • 按窗口顺序输出每个窗口的K个元素。
  5. 内存释放

    • 释放动态分配的列表、窗口和计数器数组的内存。

示例测试

示例1输入:
复制代码
4
7
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29

输出

复制代码
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19 
示例2输入:
复制代码
2
3
1 2 3 4
5 6

输出

复制代码
1 5 2 3 6 4 
示例3输入:
复制代码
3
2
10 20 30
40 50
60

输出

复制代码
10 40 60 20 50 30 

综合分析

  1. 时间复杂度 :O(MNK),M为列表数量,每个元素处理一次。
  2. 空间复杂度:O(N*K),存储所有窗口元素。
  3. 优势
    • 严格轮次分配:确保元素按轮次分配到各窗口。
    • 高效内存管理:动态分配内存,避免浪费。
    • 输入鲁棒性:处理各种输入格式,包括空行和多余空格。
  4. 适用场景:需要将多个列表元素按规则均分到多个窗口的场景。

GO

问题分析

我们需要将多个列表中的元素按特定规则分配到N个窗口,每个窗口包含K个元素。规则是穿插处理均分分配:每个列表的元素尽量均分到N个窗口,处理顺序是依次循环处理每个列表的轮次。


解题思路

  1. 输入处理:读取窗口数N、每窗口元素数K,以及多个元素列表。
  2. 轮次分配:每个列表按轮次分配元素,每次分配最多N个元素到各个窗口。
  3. 动态填充:维护每个列表的当前轮次,循环处理直到所有窗口填满。

代码实现

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// 读取输入参数
	scanner.Scan()
	N, _ := strconv.Atoi(scanner.Text()) // 窗口数
	scanner.Scan()
	K, _ := strconv.Atoi(scanner.Text()) // 每窗口元素数

	var lists [][]int
	// 读取所有列表
	for scanner.Scan() {
		line := scanner.Text()
		if line == "" {
			break
		}
		parts := strings.Split(line, " ")
		var list []int
		for _, p := range parts {
			num, _ := strconv.Atoi(p)
			list = append(list, num)
		}
		lists = append(lists, list)
	}

	// 初始化N个窗口,每个窗口最多存储K个元素
	windows := make([][]int, N)
	for i := range windows {
		windows[i] = make([]int, 0, K)
	}

	// 记录每个列表的当前轮次(从0开始)
	rounds := make([]int, len(lists))
	currentList := 0 // 当前处理的列表索引

	for {
		// 检查所有窗口是否已满
		allFull := true
		for _, w := range windows {
			if len(w) < K {
				allFull = false
				break
			}
		}
		if allFull {
			break
		}

		// 处理当前列表的当前轮次
		list := lists[currentList]
		round := rounds[currentList]
		start := round * N
		if start >= len(list) { // 当前列表已处理完所有轮次
			currentList = (currentList + 1) % len(lists)
			continue
		}

		end := start + N
		if end > len(list) {
			end = len(list)
		}
		elements := list[start:end]

		// 将元素循环分配到窗口
		for i, elem := range elements {
			windowIdx := i % N
			if len(windows[windowIdx]) < K {
				windows[windowIdx] = append(windows[windowIdx], elem)
			}
		}

		// 更新轮次并切换到下一个列表
		rounds[currentList]++
		currentList = (currentList + 1) % len(lists)
	}

	// 拼接结果并输出
	result := make([]int, 0, N*K)
	for _, w := range windows {
		result = append(result, w...)
	}
	for i, num := range result {
		if i > 0 {
			fmt.Print(" ")
		}
		fmt.Print(num)
	}
	fmt.Println()
}

代码详细解析

  1. 输入处理

    • 使用 bufio.Scanner 读取输入,前两行获取 NK
    • 后续行读取每个列表,分割为整数数组存入 lists
  2. 初始化窗口

    go 复制代码
    windows := make([][]int, N) // 创建N个窗口切片
    for i := range windows {
        windows[i] = make([]int, 0, K) // 每个窗口初始化为容量K的空切片
    }
  3. 轮次处理逻辑

    • rounds 数组记录每个列表的当前轮次。

    • 循环检查窗口是否填满,若填满则退出循环。

    • 处理当前列表的轮次,计算起始和结束索引:

      go 复制代码
      start := round * N
      end := start + N
    • 将元素循环分配到窗口(i % N 确定窗口索引)。

  4. 结果拼接

    • 遍历所有窗口,按顺序拼接元素到 result 切片。
    • 遍历输出结果,用空格分隔元素。

示例测试

示例1输入:
复制代码
4  
7  
0 1 2 3 4 5 6 7 8 9  
10 11 12 13 14 15 16 17 18 19  
20 21 22 23 24 25 26 27 28 29  

输出

复制代码
0 10 20 4 14 24 8 1 11 21 5 15 25 9 2 12 22 6 16 26 18 3 13 23 7 17 27 19  
示例2输入:
复制代码
2  
3  
1 2 3 4  
5 6  

输出

复制代码
1 5 2 3 6 4  
示例3输入:
复制代码
3  
2  
10 20 30  
40 50  
60  

输出

复制代码
10 40 60 20 50 30  

综合分析

  1. 时间复杂度 :O(MNK)

    • M为列表数量,每个元素处理一次,最多分配N*K次。
  2. 空间复杂度:O(N*K)

    • 存储所有窗口元素,总空间为N*K。
  3. 优势

    • 严格轮次分配:确保元素按规则均匀分配到窗口。
    • 高效内存管理:Go的切片动态扩展,避免内存浪费。
    • 输入鲁棒性:自动处理不同长度的输入行。
  4. 适用场景

    • 需要将多个列表元素按规则均分到多个窗口的场景,尤其适合动态数据分配需求。

更多内容:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文发表于【纪元A梦】,关注我,获取更多实用教程/资源!

相关推荐
南客先生2 分钟前
互联网大厂Java面试:RocketMQ、RabbitMQ与Kafka的深度解析
java·面试·kafka·rabbitmq·rocketmq·消息中间件
ai大佬6 分钟前
Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合
java·spring·自动化·api中转·apikey
我想进大厂11 分钟前
图论---朴素Prim(稠密图)
数据结构·c++·算法·图论
我想进大厂16 分钟前
图论---Bellman-Ford算法
数据结构·c++·算法·图论
烛阴17 分钟前
JavaScript 的 8 大“阴间陷阱”,你绝对踩过!99% 程序员崩溃瞬间
前端·javascript·面试
光而不耀@lgy22 分钟前
C++初登门槛
linux·开发语言·网络·c++·后端
Mr__Miss30 分钟前
面试踩过的坑
java·开发语言
偶尔微微一笑31 分钟前
AI网络渗透kali应用(gptshell)
linux·人工智能·python·自然语言处理·编辑器
爱喝一杯白开水32 分钟前
POI从入门到上手(一)-轻松完成Apache POI使用,完成Excel导入导出.
java·poi
啊丢_33 分钟前
C++——Lambda表达式
开发语言·c++