校招算法笔面试 | 校招笔面试真题-小红的整数配对

题目

题目链接

题目链接

小红的整数配对

题目描述

小红有一个长度为 n n n 的数组。小红初始分数为 0 0 0。小红每次选择两个整数,这两个数的差值不能超过 k k k,小红获得这两个数的乘积的分数,被选择过的数不能再选择。问小红最多能获得多少分数?

输入:

  • 第一行输入两个整数 n n n k k k
  • 第二行输入 n n n 个整数

输出:

  • 输出一个整数,表示小红能获得的最大分数

解题思路

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

  1. 关键发现:

    • 两个数的差值不能超过 k k k
    • 每个数只能使用一次
    • 需要使乘积和最大
  2. 解题策略:

    • 将数组排序
    • 从大到小遍历数组
    • 对每个数找到差值不超过 k k k 的最大数配对
    • 使用标记数组避免重复使用
  3. 具体步骤:

    • 对数组进行排序
    • 从大到小遍历每个数
    • 在未使用的数中找到差值不超过 k k k 的最大数
    • 累加乘积到答案中

代码

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

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n);
    for(int i = 0; i < n; i++) {
        cin >> a[i];
    }
    
    // 排序
    sort(a.begin(), a.end());
    
    vector<bool> used(n, false);
    long long ans = 0;
    
    // 从大到小遍历
    for(int i = n-1; i >= 0; i--) {
        if(used[i]) continue;
        
        // 找到差值不超过k的最大未使用数
        int maxj = -1;
        for(int j = i-1; j >= 0; j--) {
            if(!used[j] && a[i] - a[j] <= k) {
                maxj = j;
                break;
            }
        }
        
        if(maxj != -1) {
            ans += (long long)a[i] * a[maxj];
            used[i] = used[maxj] = true;
        }
    }
    
    cout << ans << 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 k = sc.nextInt();
        
        int[] a = new int[n];
        for(int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        
        // 排序
        Arrays.sort(a);
        
        boolean[] used = new boolean[n];
        long ans = 0;
        
        // 从大到小遍历
        for(int i = n-1; i >= 0; i--) {
            if(used[i]) continue;
            
            // 找到差值不超过k的最大未使用数
            int maxj = -1;
            for(int j = i-1; j >= 0; j--) {
                if(!used[j] && a[i] - a[j] <= k) {
                    maxj = j;
                    break;
                }
            }
            
            if(maxj != -1) {
                ans += (long)a[i] * a[maxj];
                used[i] = used[maxj] = true;
            }
        }
        
        System.out.println(ans);
    }
}
n, k = map(int, input().split())
a = list(map(int, input().split()))

# 排序
a.sort()

used = [False] * n
ans = 0

# 从大到小遍历
for i in range(n-1, -1, -1):
    if used[i]:
        continue
    
    # 找到差值不超过k的最大未使用数
    maxj = -1
    for j in range(i-1, -1, -1):
        if not used[j] and a[i] - a[j] <= k:
            maxj = j
            break
    
    if maxj != -1:
        ans += a[i] * a[maxj]
        used[i] = used[maxj] = True

print(ans)

算法及复杂度

  • 算法:贪心
  • 时间复杂度: O ( n ⋅ log ⁡ n ) \mathcal{O}(n \cdot \log n) O(nlogn) - 排序的复杂度
  • 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要存储标记数组

注意:

  1. 需要使用 long long/long 类型避免乘法溢出
  2. 从大到小遍历可以保证获得最大乘积
  3. 使用标记数组避免重复使用数字
  4. 注意差值不超过 k k k 的判断条件
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值