【贪心算法】【中位贪心】LeetCode:100123.执行操作使频率分数最大

涉及知识点

双指针
C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频
贪心算法

题目

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。
你可以对数组执行 至多 k 次操作:
从数组中选择一个下标 i ,将 nums[i] 增加 或者 减少 1 。
最终数组的频率分数定义为数组中众数的 频率 。
请你返回你可以得到的 最大 频率分数。
众数指的是数组中出现次数最多的数。一个元素的频率指的是数组中这个元素的出现次数。
示例 1:
输入:nums = [1,2,6,4], k = 3
输出:3
解释:我们可以对数组执行以下操作:

  • 选择 i = 0 ,将 nums[0] 增加 1 。得到数组 [2,2,6,4] 。
  • 选择 i = 3 ,将 nums[3] 减少 1 ,得到数组 [2,2,6,3] 。
  • 选择 i = 3 ,将 nums[3] 减少 1 ,得到数组 [2,2,6,2] 。
    元素 2 是最终数组中的众数,出现了 3 次,所以频率分数为 3 。
    3 是所有可行方案里的最大频率分数。
    示例 2:
    输入:nums = [1,4,4,2,4], k = 0
    输出:3
    解释:我们无法执行任何操作,所以得到的频率分数是原数组中众数的频率 3 。
    参数范围
    1 <= nums.length <= 105
    1 <= nums[i] <= 109
    0 <= k <= 1014

贪心算法(中位数贪心)

假定众数是x,假定nums的长度为n,将nums按升序排序。

x一定是nums中的数

我们用反证发证明。

x < nums[0]所有数先降到nums[0],再由nums[0]降到x,不如直接降到nums[0]
x > nums[n-1]所有数先升到nums[n-1],再升到x,不如只升到nums[n-1]
x在nums[i]和nums[j]之间,nums中比x小的a个数,比x大的b个数。如果a>=b,x–,可以节省a-b个操作,直到x等于nums[i];否则x++,直到x等于nums[j]。

改变的数一定是一个子数组

假定改变的数是两个子数组[i1,i2]和[i3,i4]。如果x在[i1,i2]之间,则将i4替换成i2+1,直到两个子数组挨着一起合并。如果x在[i3,i4]之间,则i1替换i3-1,直到两个子数组挨着一起合并。

x只需要考虑中位数(中位数贪心算法)

来证明贪心算法的正确性。假定x是nums[i],x前面的数a个,x后面的数b个,i变成i-1操作次数变化:b-(a-1),如果表达式大于等于0,则没必要左移。b -a+1 >= 0,即a <=b+1。同理b <=a+1。即abs(a-b)<=1,则没必要左移和右移。
即:
如果n为偶数,中间任意一个。
如果n为奇数,中间的那个。

代码

核心代码

class Solution {
public:int maxFrequencyScore(vector<int>& nums, long long k) {m_c = nums.size();sort(nums.begin(), nums.end());vector<long long> vPreSum = { 0 };for (const auto& n : nums){vPreSum.emplace_back(n+vPreSum.back());}	int iRet = 0;for (int left = 0, right = 0; left < m_c; left++){while (right <= m_c){const long long mid = left + (right - left) / 2;const long long llLessNeed = (mid - left) * nums[mid] - (vPreSum[mid] - vPreSum[left]);const long long llEqualMoreNeed = (vPreSum[right] - vPreSum[mid]) - nums[mid] * (right - mid);if (llLessNeed + llEqualMoreNeed <= k){iRet = max(iRet, right - left);right++;}else{break;}}			}return iRet;}int m_c;
};

测试用例

void Assert(const T& t1, const T& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}
}int main()
{Solution slu;vector<int> nums;int k;{Solution slu;nums = { 1,4,4,2,4 }, k = 0;auto res = slu.maxFrequencyScore(nums, k);Assert(3, res);}{Solution slu;nums = { 16, 2, 6, 20, 2, 18, 16, 8, 15, 19, 22, 29, 24, 2, 26, 19 }, k = 40;auto res = slu.maxFrequencyScore(nums, k);Assert(11, res);}{Solution slu;nums = { 1, 2, 6, 4 }, k = 3;auto res = slu.maxFrequencyScore(nums, k);Assert(3, res);}//CConsole::Out(res);
}

错误解法:二分查找+双指针

错误原因: 随着left增加targge可能减少
class Solution {
public:
int maxFrequencyScore(vector& nums, long long k) {
m_c = nums.size();
sort(nums.begin(), nums.end());
vector vPreSum = { 0 };
for (const auto& n : nums)
{
vPreSum.emplace_back(n+vPreSum.back());
}
long long llLeftSum = 0;//nums[left,target)的和,nums升序
int iRet = 0;
for (int left = 0, target = 0; left < m_c; left++)
{
while ((target < m_c) && (nums[target]*(target-left)- llLeftSum <= k))
{
const int right = BF(vPreSum,nums, target, k - (nums[target] * (target - left) - llLeftSum));
iRet = max(iRet, right - left);
llLeftSum += nums[target];
target++;
}
llLeftSum -= nums[left];
}
return iRet;
}
int BF(const vector& vPreSum,const vector& nums, int index,long long canUse)
{
int left = index, right = vPreSum.size();
while (right - left > 1)
{
const int mid = left + (right- left)/2 ;
if ((vPreSum[mid] - vPreSum[index]- nums[index] * (mid - index)) <= canUse)
{
left = mid;
}
else
{
right = mid;
}
}
return left;
}
int m_c;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/230435.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STL技术概述与入门

STL技术概述与入门 STL介绍STL六大组件初识容器算法迭代器1. vector存放内置数据类型2. Vector存放自定义数据类型3. Vector容器的嵌套 ✨ 总结 参考博文1&#xff1a;STL技术——STL概述和入门 参考博文2&#xff1a;&#xff1c;C&#xff1e;初识STL —— 标准模板库 STL介…

SpringBoot配置mysql加密之Druid方式

一、导入Druid依赖 <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.22</version> </dependency>二、生成密文 方式1. 找到存放druid jar包的目录 1-1、在目录…

【Proteus仿真】【Arduino单片机】电子称重秤

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使LCD1602液晶&#xff0c;矩阵按键、蜂鸣器、HX711称重模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示HX711称重模块检测重量…

人工智能与自动驾驶:智能出行时代的未来之路

一、前言 首先&#xff0c;我们先来说下什么是人工智能&#xff0c;人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一门研究如何使计算机系统能够模拟、仿真人类智能的技术和科学领域。它涉及构建智能代理&#xff0c;使其能够感知环境、理解和…

怎么检测DC-DC电源模块稳定性?电源测试系统测试有什么优势?

DC-DC电源模块稳定性测试 稳定性是衡量DC电源模块的重要指标&#xff0c;电源模块的稳定性直接影响着电源产品和设备的工作稳定性。DC-DC电源模块的稳定性&#xff0c;可以通过检测输出电压、输出电流、负载、波形、效率等参数来评估。 1. 静态测试方法 静态测试是通过直流电压…

【DataSophon】大数据服务组件之Flink升级

&#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&am…

性能测试QPS+TPS+事务基础知识分析

事务 就是用户某一步或几步操作的集合。不过&#xff0c;我们要保证它有一个完整意义。比如用户对某一个页面的一次请求&#xff0c;用户对某系统的一次登录&#xff0c;淘宝用户对商品的一次确认支付过程。这些我们都可以看作一个事务。那么如何衡量服务器对事务的处理能力。…

部署智能合约以及 javascript 调用合约函数(Web3项目二实战之三)

在上一篇 智能合约是Web3项目的核心要务(Web3项目二实战之二) ,我们已然为项目编写了智能合约,在攥写完智能合约后,该项目将完成了一大部分,剩下无非就是用户界面交互的内容。 然而,在码完了智能合约代码后,起着承前启后关键性的便是,前端界面与智能合约的交互。 智能…

ansible远程操作主机功能(1)

自动化运维&#xff08;playbook剧本yaml&#xff09; 是基于Python开发的配置管理和应用部署工具。自动化运维中&#xff0c;现在是异军突起。 Ansible能批量配置&#xff0c;部署&#xff0c;管理上千台主机&#xff0c;类似于Xshell的一键输入的工具&#xff0c;不需要每次…

【IOS开发】传感器 SensorKit

资源 官方文档 https://developer.apple.com/search/?qmotion%20graph&typeDocumentation SensorKit 使应用程序能够访问选定的原始数据或系统从传感器处理的指标。 步骤信息加速度计或旋转速率数据用户手腕上手表的配置物理环境中的环境光有关用户日常通勤或旅行的详细…

实验用python实现决策树和随机森林分类

1.实验目的 1.会用Python提供的sklearn库中的决策树算法对数据进行分类 2.会用Python提供的sklearn库中的随机森林算法对数据进行分类 3.会用Python提供的方法对数据进行预处理 2.设备与环境 使用Spyder并借助Python语言进行实现 3.实验原理 决策树( Decision Tree) 又称为…

【论文解读】Kvazaar 2.0: Fast and Efficient Open-Source HEVC Inter Encoder

时间&#xff1a;2020 级别&#xff1a;SCI 机构&#xff1a;Tampere University 摘要&#xff1a;高效视频编码(HEVC)是当前多媒体应用中经济的视频传输和存储的关键&#xff0c;但解决其固有的计算复杂性需要强大的视频编解码器实现。本文介绍了Kvazaar 2.0 HEVC编码器&…

RDD编程

目录 一、RDD编程基础 &#xff08;一&#xff09;RDD创建 &#xff08;二&#xff09;RDD操作 1、转换操作 2、行动操作 3、惰性机制 &#xff08;三&#xff09;持久化 &#xff08;四&#xff09;分区 &#xff08;五&#xff09;一个综合实例 二、键值对RDD &am…

SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接

系列文章&#xff1a; SpringBoot Vue前后端分离项目实战 || 一&#xff1a;Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二&#xff1a;Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三&#xff1a;Spring Boot后端与Vue前端连接 SpringBoot V…

【老牌期刊】IF:12,持续飙升,同领域期刊中的“佼佼者“,国人友好!

01 期刊概况 ARTIFICIAL INTELLIGENCE REVIEW ​ 【出版社】Springer 【ISSN】0269-2821 【EISSN】1573-7462 【检索情况】SCI&EI&Scopus在检 【WOS收录年份】1988年 【出刊频率】双月刊&#xff0c;最新一期December 2023 【期刊官网】 https://link.springe…

【Linux】进程周边005之环境变量

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.环境变量是什么&#xff1…

太阳能电池效能IV测试PV检测太阳光模拟器

目录 概述 一、系统组成 产品特点&#xff1a; 技术参数 数字源表 本系统支持Keithley24xx系列源表 标准太阳能电池 低阻测试夹具 自动化测试软件 概述 太阳能光伏器件的所有性能表征手段中&#xff0c;IV特性测试无疑是最直观、最有效、最被广泛应用的一种…

【OS】操作系统总复习笔记

操作系统总复习 文章目录 操作系统总复习一、考试题型1. 论述分析题2. 计算题3. 应用题 二、操作系统引论&#xff08;第1章&#xff09;2.1 操作系统的发展过程2.2 操作系统定义2.3 操作系统的基本特性2.3.1 并发2.3.2 共享2.3.3 虚拟2.3.4 异步 2.4 OS的功能2.5 OS结构2.5 习…

Android studio 按键控制虚拟LED

一、activity_main.xml代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.a…

《Linux C编程实战》笔记:进程操作之创建进程

进程是一个动态的实体&#xff0c;是程序的一次执行过程。进程是操作系统资源分配的基本单位。 以下是一些概念&#xff0c;我就直接抄书了 进程是操作系统的知识&#xff0c;简单理解的话&#xff0c;你写的代码运行起来算一个进程&#xff1f; 创建进程 每个进程由进程ID号…