可上 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1441了解算法冲刺训练(备注【CSDN】否则不通过)

相关推荐阅读

题目练习网址:【哈希集合】2025C-最大N个数与最小N个数的和

题目描述与示例

题目描述

给定一个数组,编写一个函数来计算它的最大N个数与最小N个数的和。你需要对数组进行去重。

输入描述

第一行输入MM标识数组大小

第二行输入M个数,标识数组内容

第三行输入NN表达需要计算的最大、最小N个数

输出描述

输出最大N个数与最小N个数的和。

补充说明

数组中数字范围[0,1000]

最大N个数与最小N个数不能有重叠,如有重叠返回-1

示例

输入

5
95 88 83 64 100
2

输出

342

解题思路

直白、简单的题目。主要考察以下几个知识点

  1. 哈希集合去重
  2. 去重后的结果再次排序得到新列表lst_new
  3. lst_new的长度必须大于2*N
  4. 计算最大的N个数和最小的N个数的和

代码

Python

# 欢迎来到「欧弟算法 - 华为OD全攻略」,收录华为OD题库、面试指南、八股文与学员案例!
# 地址:https://www.odalgo.com
# 华为OD机试刷题网站:https://www.algomooc.com
# 添加微信 278166530 获取华为 OD 笔试真题题库和视频

# 题目:2023C/2024D/2025C-最大N个数与最小N个数的和
# 分值:100
# 作者:闭着眼睛学数理化
# 算法:哈希集合,排序
# 代码看不懂的地方,请直接在群上提问


m = int(input())
lst = list(map(int, input().split()))
n = int(input())

# 使用set进行去重,然后对去重后的结果进行排序
lst_new = sorted(set(lst))

# 如果lst_new的长度小于2*n
# 说明最大N个数和最小N个数出现了重叠,输出-1
if len(lst_new) < 2*n:
    print(-1)
# 否则,使用切片和sum(),计算最大N个数和最小N个数的和
else:
    print(sum(lst_new[:n]) + sum(lst_new[len(lst_new)-n:]))

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int m = scanner.nextInt();
        
        List<Integer> lst = new ArrayList<>();
        for (int i = 0; i < m; ++i) {
            lst.add(scanner.nextInt());
        }

        int n = scanner.nextInt();
        
        // 使用 Set 进行去重,并对其进行排序
        Set<Integer> uniqueSet = new TreeSet<>(lst);
        List<Integer> lstNew = new ArrayList<>(uniqueSet);

        if (lstNew.size() < 2 * n) {
            System.out.println(-1);
        } else {
            long sum = 0;
            for (int i = 0; i < n; ++i) {
                sum += lstNew.get(i) + lstNew.get(lstNew.size() - 1 - i);
            }
            System.out.println(sum);
        }
    }
}

C++

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

int main() {
    int m, n;
    cin >> m;
    
    vector<int> lst(m);
    for (int i = 0; i < m; ++i) {
        cin >> lst[i];
    }

    cin >> n;

    // 使用 set 进行去重,并对其进行排序
    set<int> uniqueSet(lst.begin(), lst.end());
    vector<int> lstNew(uniqueSet.begin(), uniqueSet.end());
    sort(lstNew.begin(), lstNew.end());

    if (lstNew.size() < 2 * n) {
        cout << -1 << endl;
    } else {
        long long sum = 0;
        for (int i = 0; i < n; ++i) {
            sum += lstNew[i] + lstNew[lstNew.size() - 1 - i];
        }
        cout << sum << endl;
    }

    return 0;
}

C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/*
    说明(关于 C 语言中替代 C++ set 的做法):
    - C 语言没有现成的 set 容器,为实现“使用 set 进行去重,并对其进行排序”的效果,
      我们先对原数组进行升序排序(qsort),再线性扫描压缩相邻重复元素,得到去重后的有序数组。
*/

/* qsort 比较函数:升序排序 */
static int cmp_int_asc(const void *a, const void *b) {
    int ia = *(const int *)a;
    int ib = *(const int *)b;
    if (ia < ib) return -1;
    if (ia > ib) return 1;
    return 0;
}

int main(void) {
    int m, n;

    /* 读入 m */
    if (scanf("%d", &m) != 1) {
        return 0; /* 输入异常时直接结束 */
    }

    /* 读入 m 个整数 */
    int *lst = (int *)malloc(sizeof(int) * (m > 0 ? m : 1));
    if (!lst) {
        return 0; /* 内存分配失败,直接结束 */
    }
    for (int i = 0; i < m; ++i) {
        scanf("%d", &lst[i]);
    }

    /* 读入 n */
    scanf("%d", &n);

    /*
        使用 set 进行去重,并对其进行排序
        —— 在 C 中的等价实现:
        1) 先对 lst 升序排序;
        2) 再将相邻相同的元素压缩掉,得到去重后的有序数组 lstNew。
    */
    qsort(lst, m, sizeof(int), cmp_int_asc);

    // 统计去重后的大小(先遍历计算 unique 的个数)
    int unique_cnt = 0;
    if (m > 0) {
        unique_cnt = 1;
        for (int i = 1; i < m; ++i) {
            if (lst[i] != lst[i - 1]) {
                ++unique_cnt;
            }
        }
    }

    // 分配去重后的数组并填充
    int *lstNew = (int *)malloc(sizeof(int) * (unique_cnt > 0 ? unique_cnt : 1));
    if (!lstNew) {
        free(lst);
        return 0;
    }
    int idx = 0;
    if (m > 0) {
        lstNew[idx++] = lst[0];
        for (int i = 1; i < m; ++i) {
            if (lst[i] != lst[i - 1]) {
                lstNew[idx++] = lst[i];
            }
        }
    }

    // 此时 lstNew 已经是升序且元素唯一
    // 判断是否满足 2*n 的配对需求
    if (unique_cnt < 2 * n) {
        printf("-1\n");
    } else {
        long long sum = 0; // 使用 long long 存储求和,避免溢出
        for (int i = 0; i < n; ++i) {
            sum += (long long)lstNew[i] + (long long)lstNew[unique_cnt - 1 - i];
        }
        printf("%lld\n", sum);
    }

    free(lstNew);
    free(lst);
    return 0;
}

Node JavaScript

"use strict";

/**
 * 读取标准输入并解析为字符串数组
 */
const fs = require("fs");
const input = fs.readFileSync(0, "utf8").trim().split(/\s+/);

// 指针用于按顺序取数
let idx = 0;

// 读入 m
const m = Number(input[idx++]);

const uniq = new Set();
for (let i = 0; i < m; ++i) {
  const val = BigInt(input[idx++]);
  uniq.add(val); // 去重
}

// 读入 n
const n = Number(input[idx++]);

// 将去重结果转为数组并排序(升序)
const lstNew = Array.from(uniq);
lstNew.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));

// 若去重后的元素个数小于 2*n,则无法两两配对,输出 -1
if (lstNew.length < 2 * n) {
  console.log(-1);
} else {
  // 从两端向中间配对求和:最小配最大的、次小配次大的
  let sum = 0n; 
  for (let i = 0; i < n; ++i) {
    sum += lstNew[i] + lstNew[lstNew.length - 1 - i];
  }
  // 输出时转为字符串,避免 BigInt 与默认输出不兼容
  console.log(sum.toString());
}

Go

package main

import (
        "bufio"
        "fmt"
        "os"
        "sort"
)

func main() {
        in := bufio.NewReader(os.Stdin)

        var m int
        if _, err := fmt.Fscan(in, &m); err != nil {
                return
        }

        // 使用 map 充当 Set 进行去重(键为元素值,值为是否出现)
        unique := make(map[int64]bool)
        for i := 0; i < m; i++ {
                var x int64
                fmt.Fscan(in, &x)
                unique[x] = true
        }

        var n int
        fmt.Fscan(in, &n)

        // 将去重后的键转为切片并进行升序排序
        lstNew := make([]int64, 0, len(unique))
        for k := range unique {
                lstNew = append(lstNew, k)
        }
        sort.Slice(lstNew, func(i, j int) bool { return lstNew[i] < lstNew[j] })

        // 判断是否满足 2*n 个可配对元素
        if len(lstNew) < 2*n {
                fmt.Println(-1)
                return
        }

        // 从两端向中间配对求和
        var sum int64 = 0
        for i := 0; i < n; i++ {
                sum += lstNew[i] + lstNew[len(lstNew)-1-i]
        }
        fmt.Println(sum)
}

时空复杂度

时间复杂度:O(MlogM)。排序所需时间复杂度

空间复杂度:O(M)


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华子OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务1000+同学成功上岸!

  • 课程讲师为全网200w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 90+天陪伴式学习,100+直播课时,300+动画图解视频,500+LeetCode经典题,500+华为OD真题/大厂真题,还有简历修改、模拟面试、陪伴小群、资深HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1441或了解更多

更多推荐