2023-04-08:小红有n个朋友, 她准备开个宴会,邀请一些朋友,
i号朋友的愉悦值为a[i],财富值为b[i],
如果两个朋友同时参加宴会,这两个朋友之间的隔阂是其财富值差值的绝对值,
宴会的隔阂值,是财富差距最大的两人产生的财富值差值的绝对值,
宴会的愉悦值,是所有参加宴会朋友的愉悦值总和。
小红可以邀请任何人,
希望宴会的愉悦值不能小于k的情况下, 宴会的隔阂值能最小是多少?
如果做不到,返回-1。
1 <= n <= 2 * 10^5,
1 <= 愉悦值、财富值 <= 10^9,
1 <= k <= 10^14。
来自蚂蚁金服。

答案2023-04-08:

方法一:暴力枚举

思路:

对于每一个可能的区间,计算区间中 bb 数组元素的最大值和最小值,然后计算跨度并统计愉悦值。记录跨度最小的区间的元素和与跨度,最后返回跨度最小的值。

步骤:

1.使用递归函数枚举所有可能的区间,函数参数包括数组 a、数组 b、当前递归到的位置 i、剩余需要选择的元素个数 restr,以及已经选过的区间中的最小值 min 和最大值 max。
2.当需要选择的元素个数 rest 小于等于 0 时,返回跨度最小的区间对应数组 b 的元素的最大值和最小值之差;
3.当递归到数组 a 的末尾时,返回一个足够大的数(这里使用了 Rust 中整型类型 i32 的最大值)表示无法选出符合要求的区间;
4.否则,分别计算选择当前位置的元素和不选择当前位置的元素两种情况下所能得到的跨度最小的区间,然后取两者的最小值作为函数的返回值。

时间复杂度:O(2^n),其中 n 是数组长度。

空间复杂度:O(n)。

方法二:二分答案

思路:

对于每一个可能的区间跨度 x,我们可以判断是否有一个区间的元素和最接近 k 且其跨度不大于 x。具体实现时,先将数组 b 按照元素大小排序,然后利用二分查找的思想,在排序后的数组上二分答案。

步骤:

1.将数组 b 按照元素大小排序,并记录 b 数组的最小值和最大值;
2.使用二分答案法,在区间 [0,max−min] 上进行二分,其中 max 和 min 分别为 b 数组中的最大值和最小值;
3.对于每一个二分得到的可能的跨度 x,计算在跨度不大于 x 的情况下,宴会的愉悦值能否大于等于 k。具体实现时,使用双指针法维护当前区间的左右端点,计算当前区间内 a 数组元素的和并记录其最大值;
4.如果在跨度不大于 x 的情况下宴会的愉悦值大于等于 k,则更新答案,并将区间左端点右移;
5.否则,将区间右端点右移。

时间复杂度:O(nlognlogV),其中 n 是数组长度,V 是数组元素的最大值。

空间复杂度:O(n)。

方法三:滑动窗口

思路:

我们可以使用双指针法在 b 数组上维护一个区间,使得该区间的财富值差距不大于当前尝试的跨度,并计算在该区间中元素值和能否大于等于 k。具体实现时,先将数组 b 按照元素大小排序,然后使用两个指针 l 和 r 维护当前区间,用变量 happy 记录当前区间内元素值之和,每次将指针向右移动时对 happy 进行更新,直到找到一个满足愉悦值大于等于 k 的区间。

步骤:

1.将数组 b 按照元素大小排序;
2.使用双指针法,在数组 b 上维护一个区间,使得该区间的财富值差距不大于当前尝试的跨度,并计算在该区间中元素值和能否大于等于 k。具体实现时,使用两个指针 l 和 rr 维护当前区间,用变量 happy 记录当前区间内元素值之和。每次将指针向右移动时对 happy 进行更新,并在 happy≥k 的情况下更新答案;
3.如果找到了一个满足愉悦值大于等于 k 的区间,则返回该区间的跨度;否则返回 −1。

时间复杂度:O(nlogn),其中 n 是数组长度。

空间复杂度:O(n)。

三种方法分析

从时间复杂度和空间复杂度两个方面来看,方法二和方法三都比方法一要好得多。在实际应用中,我们应该优先选择方法二或方法三。

rust完整代码如下:

fn less_gap1(a: &Vec<i32>, b: &Vec<i32>, k: i32) -> i32 {
let ans = process(a, b, 0, k, std::i32::MAX, std::i32::MIN);
return if ans < std::i32::MAX as i64 {
ans as i32
} else {
-1
};
} fn process(a: &Vec<i32>, b: &Vec<i32>, i: usize, rest: i32, min: i32, max: i32) -> i64 {
if rest <= 0 {
(max - min).abs() as i64
} else if i == a.len() {
std::i32::MAX as i64
} else {
let p1 = process(a, b, i + 1, rest, min, max);
let p2 = process(a, b, i + 1, rest - a[i], min.min(b[i]), max.max(b[i]));
p1.min(p2)
}
} fn less_gap2(a: &Vec<i32>, b: &Vec<i32>, k: i64) -> i32 {
let n = a.len();
let mut f = vec![vec![0; 2]; n];
let mut min = b[0];
let mut max = b[0];
for i in 0..n {
f[i][0] = a[i];
f[i][1] = b[i];
min = min.min(b[i]);
max = max.max(b[i]);
}
f.sort_by_key(|x| x[1]); let (mut l, mut r) = (0, max - min);
let mut ans = -1;
while l <= r {
let m = (l + r) / 2;
if max_happy(&f, m) >= k {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
} fn max_happy(f: &Vec<Vec<i32>>, limit: i32) -> i64 {
let n = f.len();
let mut sum = 0;
let mut ans = 0;
let mut r = 0; for l in 0..n {
while r < n && f[r][1] - f[l][1] <= limit {
sum += f[r][0];
r += 1;
}
ans = ans.max(sum);
sum -= f[l][0];
r = r.max(l + 1);
} return ans as i64;
} fn less_gap3(a: &Vec<i32>, b: &Vec<i32>, k: i64) -> i32 {
let n = a.len();
let mut f = vec![vec![0; 2]; n];
for i in 0..n {
f[i][0] = a[i];
f[i][1] = b[i];
}
f.sort_by_key(|x| x[1]); let (mut ans, mut happy) = (std::i32::MAX, 0_i64);
let (mut l, mut r) = (0, 0);
while l < n {
while r < n && happy < k {
happy += f[r][0] as i64;
r += 1;
}
if happy >= k {
ans = ans.min(f[r - 1][1] - f[l][1]);
}
happy -= f[l][0] as i64;
l += 1;
} return if ans == std::i32::MAX { -1 } else { ans };
} fn random_array(n: usize, v: i32) -> Vec<i32> {
let mut arr = vec![0; n];
for i in 0..n {
arr[i] = (rand::random::<f64>() * v as f64 + 1.0) as i32;
}
return arr;
} fn main() {
const N: usize = 15;
const V: i32 = 20;
const TEST_TIME: i32 = 5000; println!("功能测试开始");
for _ in 0..TEST_TIME {
let n = rand::random::<usize>() % N + 1;
let a = random_array(n, V);
let b = random_array(n, V);
let k = rand::random::<usize>() % (n * V as usize) + 1;
let ans1 = less_gap1(&a, &b, k as i32);
let ans2 = less_gap2(&a, &b, k as i64);
let ans3 = less_gap3(&a, &b, k as i64);
if ans1 != ans2 || ans1 != ans3 {
println!("出错了!");
println!("a = {:?}", a);
println!("b = {:?}", b);
println!("k = {}", k);
println!("ans1 = {}", ans1);
println!("ans2 = {}", ans2);
println!("ans3 = {}", ans3);
return;
}
}
println!("功能测试结束");
}

2023-04-08:社交网络中的最优邀请策略探究。本文以小红准备开宴会为例,提出一种基于贪心算法和二分查找的解决方案,帮助读者在保证愉悦值不低于k的前提下,最小化宴会的阶层差距。的更多相关文章

  1. bootstrap中container 类和container-fluid类的区别container类所谓的自适应也是通过margin的改变来完成,container-fluid类的百分百宽度是指在固有的15px的padding前提下宽度总是当前视口的宽度。

    container 类和container-fluid类的区别体现在是否有随视口宽度改变的margin存在. container类所谓的自适应也是通过margin的改变来完成,container-fl ...

  2. 腾讯优图&港科大提出一种基于深度学习的非光流 HDR 成像方法

    目前最好的高动态范围(HDR)成像方法通常是先利用光流将输入图像对齐,随后再合成 HDR 图像.然而由于输入图像存在遮挡和较大运动,这种方法生成的图像仍然有很多缺陷.最近,腾讯优图和香港科技大学的研究 ...

  3. C语言实现 二分查找数组中的Key值(递归和非递归)

    基本问题:使用二分查找的方式,对数组内的值进行匹配,如果成功,返回其下标,否则返回 -1.请使用递归和非递归两种方法说明. 非递归代码如下: #include <stdio.h> int ...

  4. 不修改模板的前提下修改VisualState中的某些值

    原文链接:不修改模板的前提下修改VisualState中的某些值 - 超威蓝火 UWP里有一件非常令人不爽的事,大部分控件只提供了Normal状态下的Background,Foreground,Bor ...

  5. 删除链表中全部值为k的节点

    1. 问题描写叙述 给定一个单链表,删除当中值为k的全部节点.比如:1→2→6→3→4→5→61 \to 2 \to 6 \to 3 \to 4 \to 5 \to 6,删除当中值为6的节点,返回:1 ...

  6. LeetCode 周赛 342(2023/04/23)容斥原理、计数排序、滑动窗口、子数组 GCB

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 前天刚举办 2023 年力扣杯个人 SOLO 赛,昨天周赛就出了一场 Easy - Ea ...

  7. hdu6003 Problem Buyer 贪心 给定n个区间,以及m个数,求从n个区间中任意选k个区间,满足m个数都能在k个区间中找到一个包含它的区间,如果一个区间包含了x,那么 该区间不能再去包含另一个数,即k>=m。求最小的k。如果不存在这样的k,输出“IMPOSSIBLE!”。

    /** 题目:hdu6003 Problem Buyer 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6003 题意:给定n个区间,以及m个数,求从n个区 ...

  8. How Javascript works (Javascript工作原理) (二) 引擎,运行时,如何在 V8 引擎中书写最优代码的 5 条小技巧

    个人总结: 一个Javascript引擎由一个标准解释程序,或者即时编译器来实现. 解释器(Interpreter): 解释一行,执行一行. 编译器(Compiler): 全部编译成机器码,统一执行. ...

  9. 从算法入手讲解如何在SQL Server中实现最优最简

    算法是计算机科学中一个重要的研究方向,是解决复杂问题的关键.在计算机世界中,算法无处不在.数据库是存储数据和执行大批量计算的场所,在数据库中使用一些简单的SQL命令,进行存储.查询.统计.以解决现实世 ...

  10. POJ_3685_Matrix_(二分,查找第k大的值)

    描述 http://poj.org/problem?id=3685 一个n*n的矩阵,(i,j)的值为i*i+100000*i+j*j-100000*j+i*j,求第m小的值. Matrix Time ...

随机推荐

  1. GDB使用详解

    来源:GDB使用详解 - 知乎 (zhihu.com) 1. 概述 ​ GDB 全称"GNU symbolic debugger",从名称上不难看出,它诞生于 GNU 计划(同时诞 ...

  2. EF6 Code First Migrations

    参考地址:https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/migrations/ 1.启动Migrations Enable- ...

  3. Gin使用及源码简析

    1. Gin简介 前面通过两篇文章分享了Golang HTTP编程的路由分发.请求/响应处理. Golang HTTP编程及源码解析-路由分发 Golang HTTP编程及源码解析-请求/响应处理 可 ...

  4. Apache Kafka教程--Kafka新手入门

    Apache Kafka教程--Kafka新手入门 Kafka Assistant 是一款 Kafka GUI 管理工具--管理Broker,Topic,Group.查看消费详情.监控服务器状态.支持 ...

  5. 认识内存和Cache

    认识内存和Cache 操作系统学习笔记,如有错误,还望指出. 我们有什么问题 什么是内存? 什么是Cache? 为什么需要Cache? 程序的局部性原理 这是个前置芝士点. 定义: 程序的局部性原理是 ...

  6. Linux系统下祼机安装mysql8.0和docker mysql 8.0 性能差异对比~

    环境准备 准备两台服务器环境,配置相同,分别安装Centos7,mysql8.0,docker mysql 8.0 准备测试代码 public class Chat { public static l ...

  7. Github Copilot 比在座各位更会写代码。jpg

    之前大佬和我安利过 Copilot, 作为一个能用就行的践行者, 我一贯对这些东西都不太感兴趣. 就如我多年VS Code写各种编程语言, jetbrains 全家桶我都懒得搞~ 不过最近看到过Cha ...

  8. SpringCloud Fegin 负载均衡

    Spring Cloud Ribbon 和 Spring Cloud Hystrix 在微服务中实现了客户端负载均衡的服务调用以及通过断路器来保护微服务应用.这两者作为基础工具类框架广泛地应用在各个微 ...

  9. 【Eolink】Apikit V10.8.0 版本发布!增加支持 DUBBO、TCP、SOAP 、HSF、UDP 的接口协议

    Apikit 最新功能来袭! 我们在这个版本实现了接口管理和测试能力的全面升级,包括且不限于: 新增功能速览: 增加支持 DUBBO.TCP.SOAP .HSF.UDP 接口文档和协议 接口文档可自动 ...

  10. 武装你的WEBAPI-ODATA聚合查询

    本文属于OData系列 目录 武装你的WEBAPI-OData入门 武装你的WEBAPI-OData便捷查询 武装你的WEBAPI-OData分页查询 武装你的WEBAPI-OData资源更新Delt ...