【单调栈】LeetCode:2818操作使得分最大

2023-12-23 08:15

本文主要是介绍【单调栈】LeetCode:2818操作使得分最大,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者推荐

map|动态规划|单调栈|LeetCode975:奇偶跳

涉及知识点

单调栈

题目

给你一个长度为 n 的正整数数组 nums 和一个整数 k 。
一开始,你的分数为 1 。你可以进行以下操作至多 k 次,目标是使你的分数最大:
选择一个之前没有选过的 非空 子数组 nums[l, …, r] 。
从 nums[l, …, r] 里面选择一个 质数分数 最高的元素 x 。如果多个元素质数分数相同且最高,选择下标最小的一个。
将你的分数乘以 x 。
nums[l, …, r] 表示 nums 中起始下标为 l ,结束下标为 r 的子数组,两个端点都包含。
一个整数的 质数分数 等于 x 不同质因子的数目。比方说, 300 的质数分数为 3 ,因为 300 = 2 * 2 * 3 * 5 * 5 。
请你返回进行至多 k 次操作后,可以得到的 最大分数 。
由于答案可能很大,请你将结果对 109 + 7 取余后返回。
示例 1:
输入:nums = [8,3,9,3,8], k = 2
输出:81
解释:进行以下操作可以得到分数 81 :

  • 选择子数组 nums[2, …, 2] 。nums[2] 是子数组中唯一的元素。所以我们将分数乘以 nums[2] ,分数变为 1 * 9 = 9 。
  • 选择子数组 nums[2, …, 3] 。nums[2] 和 nums[3] 质数分数都为 1 ,但是 nums[2] 下标更小。所以我们将分数乘以 nums[2] ,分数变为 9 * 9 = 81 。
    81 是可以得到的最高得分。
    示例 2:
    输入:nums = [19,12,14,6,10,18], k = 3
    输出:4788
    解释:进行以下操作可以得到分数 4788 :
  • 选择子数组 nums[0, …, 0] 。nums[0] 是子数组中唯一的元素。所以我们将分数乘以 nums[0] ,分数变为 1 * 19 = 19 。
  • 选择子数组 nums[5, …, 5] 。nums[5] 是子数组中唯一的元素。所以我们将分数乘以 nums[5] ,分数变为 19 * 18 = 342 。
  • 选择子数组 nums[2, …, 3] 。nums[2] 和 nums[3] 质数分数都为 2,但是 nums[2] 下标更小。所以我们将分数乘以 nums[2] ,分数变为 342 * 14 = 4788 。
    4788 是可以得到的最高的分。
    参数范围
    1 <= nums.length == n <= 105
    1 <= nums[i] <= 105
    1 <= k <= min(n * (n + 1) / 2, 109)

单调栈

时间复杂度😮(nlogn)
静态变量vPrime 记录所有质数。
vPriCount 记录nums各数的质量分数。vPriCount也可以弄成静态成员变量。
我们枚举各子数组的最大质量分数,如果有多个最大质量分数,取下标最小的。即:
left为从右向左第一个大于等于vPriCount[i]的下标,不存在为-1。
right为从左向右第一个大于vPriCount[i]的下标,不存在为m_c。
子数组(li,ri)就是符合条件的子数组,li取值范围(left,i],ri取值范围[i,right)。
我们按的nums[i]降序操作 最大质量分数为vPriCount[i]的子数组。

代码

核心代码

class CRangIndex
{
public:template<class _Pr>CRangIndex(const vector<int>& nums, _Pr CurIndexCmpStackTopIndex){m_c = nums.size();m_vLeft.assign(m_c, -1);m_vRight.assign(m_c, m_c);stack<int> sta;for (int i = 0; i < m_c; i++){while (sta.size() && (CurIndexCmpStackTopIndex(i, sta.top()))){m_vRight[sta.top()] = i;sta.pop();}if (sta.size()){m_vLeft[i] = sta.top();}sta.emplace(i);}}int m_c;vector<int> m_vLeft, m_vRight;//vLeft[i] 从右向左第一个小于nums[i] ;vRight[i] 是第一个小于等于nums[i]。
};vector<int> CreatePrime(int iMax)
{vector<int> vPrime = { 2 };for (int i = 3; i <= iMax; i++){bool b = true;for (const auto& n : vPrime){if (0 == i % n){b = false;break;}}if (b){vPrime.emplace_back(i);}}return vPrime;
}template<int MOD = 1000000007>
class C1097Int
{
public:C1097Int(long long llData = 0) :m_iData(llData% MOD){}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o){return C1097Int((m_iData + MOD - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((long long)m_iData * o.m_iData) % MOD;return *this;}bool operator<(const C1097Int& o)const{return m_iData < o.m_iData;}C1097Int pow(long long n)const{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}int ToInt()const{return m_iData;}
private:int m_iData = 0;;
};class Solution {
public:int maximumScore(vector<int>& nums, int k) {m_c = nums.size();vector<int> vPriCount;{static vector<int> vPrime = CreatePrime(1000 * 100);for (const auto& n : nums){int tmp = n;int iNum = 0;for (const auto& pr : vPrime){if (pr * pr > tmp){break;}if (0 == tmp % pr){while (0 == tmp % pr){tmp /= pr;}iNum++;}}vPriCount.emplace_back(iNum + (tmp > 1));}}CRangIndex ri(vPriCount, [&](int i1, int i2) {return vPriCount[i1] > vPriCount[i2]; });std::multimap<int, int, greater<int>> mValueIndex;for (int i = 0; i < ri.m_c; i++){mValueIndex.emplace(nums[i], i);}C1097Int<> biRet=1;for (const auto& [value, i] : mValueIndex){const long long llSubArrCount = ((long long)i - ri.m_vLeft[i]) * (ri.m_vRight[i] - i);const long long llOpeCount = min((long long)k, llSubArrCount);biRet *= C1097Int<>(value).pow(llOpeCount);k -= llOpeCount;if (0 == k){break;}}return biRet.ToInt();}int m_c;
};

测试用例

template<class T>
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()
{vector<int> nums;int k;{Solution slu;nums = { 8, 3, 9, 3, 8 };k = 2;auto res = slu.maximumScore(nums, k);Assert(81, res);}{Solution slu;nums = { 19,12,14,6,10,18 };k = 3;auto res = slu.maximumScore(nums, k);Assert(4788, res);}//CConsole::Out(res);
}

2023年8月

template<int MOD = 1000000007>
class C1097Int
{
public:C1097Int(long long llData = 0) :m_iData(llData% MOD){}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o){return C1097Int((m_iData + MOD - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((long long)m_iData * o.m_iData) % MOD;return *this;}bool operator<(const C1097Int& o)const{return m_iData < o.m_iData;}C1097Int pow(int n)const{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}int ToInt()const{return m_iData;}
private:int m_iData = 0;;
};template<int MOD = 1000000007>
int operator+(int iData, const C1097Int<MOD>& int1097)
{int iRet = int1097.operator+(C1097Int<MOD>(iData)).ToInt();return iRet;
}template<int MOD = 1000000007>
int& operator+=(int& iData, const C1097Int<MOD>& int1097)
{iData = int1097.operator+(C1097Int<MOD>(iData)).ToInt();return iData;
}template<int MOD = 1000000007>
int operator*(int iData, const C1097Int<MOD>& int1097)
{int iRet = int1097.operator*(C1097Int(iData)).ToInt();return iRet;
}template<int MOD = 1000000007>
int& operator*=(int& iData, const C1097Int<MOD>& int1097)
{iData = int1097.operator*(C1097Int(iData)).ToInt();return iData;
}class Solution {
public:int maximumScore(vector<int>& nums, int k) {m_c = nums.size();vector<int> vScore;for ( int n : nums){int iScore = 0;for (int i = 2; i * i <= n; i++){if (0 != n % i){continue;}iScore++;while (0 == n % i){n /= i;}}if (n > 1){iScore++;}vScore.emplace_back(iScore);}stack<int> sta;vector<int> vLeft(m_c), vRight(m_c, m_c);for (int i = 0 ; i < m_c ; i++ ){while (sta.size() && (vScore[sta.top()] < vScore[i])){vRight[sta.top()] = i;sta.pop();}vLeft[i] = sta.size() ? sta.top() : -1;sta.emplace(i);			}std::map<int, long long,std::greater<int>> mValueNum;for (int i = 0; i < m_c; i++){mValueNum[nums[i]] += (i - vLeft[i])*(long long)(vRight[i] - i);}C1097Int<> biRet = 1;while (k > 0){for (auto it : mValueNum){long long llMulMul = min((long long)k, it.second);k -= llMulMul;auto cur = C1097Int<>(it.first).pow((int)llMulMul);biRet *= cur;}}return biRet.ToInt();}int m_c;
};

使用封装类后

template<int MOD = 1000000007>
class C1097Int
{
public:C1097Int(long long llData = 0) :m_iData(llData% MOD){}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o){return C1097Int((m_iData + MOD - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((long long)m_iData * o.m_iData) % MOD;return *this;}bool operator<(const C1097Int& o)const{return m_iData < o.m_iData;}C1097Int pow(long long n)const{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}int ToInt()const{return m_iData;}
private:int m_iData = 0;;
};class CRangIndex
{
public:template<class _Pr>CRangIndex(int iVectorSize, _Pr CurIndexCmpStackTopIndex){m_c = iVectorSize;m_vLeft.assign(m_c, -1);m_vRight.assign(m_c, m_c);stack<int> sta;for (int i = 0; i < m_c; i++){while (sta.size() && (CurIndexCmpStackTopIndex(i, sta.top()))){m_vRight[sta.top()] = i;sta.pop();}if (sta.size()){m_vLeft[i] = sta.top();}sta.emplace(i);}}template<class _Pr>CRangIndex(const vector<int>& nums, _Pr CurValueCmpStackTopValue){m_c = nums.size();m_vLeft.assign(m_c, -1);m_vRight.assign(m_c, m_c);stack<int> sta;for (int i = 0; i < m_c; i++){while (sta.size() && (CurValueCmpStackTopValue(nums[i], nums[sta.top()]))){m_vRight[sta.top()] = i;sta.pop();}if (sta.size()){m_vLeft[i] = sta.top();}sta.emplace(i);}}int m_c;vector<int> m_vLeft, m_vRight;//vLeft[i] 从右向左第一个小于nums[i] ;vRight[i] 是第一个小于等于nums[i]。
};vector<int> CreatePrime(int iMax)
{vector<int> vPrime = { 2 };for (int i = 3; i <= iMax; i++){bool b = true;for (const auto& n : vPrime){if (0 == i % n){b = false;break;}}if (b){vPrime.emplace_back(i);}}return vPrime;
}
class Solution {
public:int maximumScore(vector<int>& nums, int k) {m_c = nums.size();vector<int> vPriCount;{static vector<int> vPrime = CreatePrime(1000 * 100);for (const auto& n : nums){int tmp = n;int iNum = 0;for (const auto& pr : vPrime){if (pr * pr > tmp){break;}if (0 == tmp % pr){while (0 == tmp % pr){tmp /= pr;}iNum++;}}vPriCount.emplace_back(iNum + (tmp > 1));}}CRangIndex ri(vPriCount, std::greater<>());std::multimap<int, int, greater<int>> mValueIndex;for (int i = 0; i < ri.m_c; i++){mValueIndex.emplace(nums[i], i);}C1097Int<> biRet=1;for (const auto& [value, i] : mValueIndex){const long long llSubArrCount = ((long long)i - ri.m_vLeft[i]) * (ri.m_vRight[i] - i);const long long llOpeCount = min((long long)k, llSubArrCount);biRet *= C1097Int<>(value).pow(llOpeCount);k -= llOpeCount;if (0 == k){break;}}return biRet.ToInt();}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++ 实现。

这篇关于【单调栈】LeetCode:2818操作使得分最大的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/527329

相关文章

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python 中的 with open文件操作的最佳实践

《Python中的withopen文件操作的最佳实践》在Python中,withopen()提供了一个简洁而安全的方式来处理文件操作,它不仅能确保文件在操作完成后自动关闭,还能处理文件操作中的异... 目录什么是 with open()?为什么使用 with open()?使用 with open() 进行

Linux ls命令操作详解

《Linuxls命令操作详解》通过ls命令,我们可以查看指定目录下的文件和子目录,并结合不同的选项获取详细的文件信息,如权限、大小、修改时间等,:本文主要介绍Linuxls命令详解,需要的朋友可... 目录1. 命令简介2. 命令的基本语法和用法2.1 语法格式2.2 使用示例2.2.1 列出当前目录下的文

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

Java使用Curator进行ZooKeeper操作的详细教程

《Java使用Curator进行ZooKeeper操作的详细教程》ApacheCurator是一个基于ZooKeeper的Java客户端库,它极大地简化了使用ZooKeeper的开发工作,在分布式系统... 目录1、简述2、核心功能2.1 CuratorFramework2.2 Recipes3、示例实践3

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Python使用DrissionPage中ChromiumPage进行自动化网页操作

《Python使用DrissionPage中ChromiumPage进行自动化网页操作》DrissionPage作为一款轻量级且功能强大的浏览器自动化库,为开发者提供了丰富的功能支持,本文将使用Dri... 目录前言一、ChromiumPage基础操作1.初始化Drission 和 ChromiumPage

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

Redis中管道操作pipeline的实现

《Redis中管道操作pipeline的实现》RedisPipeline是一种优化客户端与服务器通信的技术,通过批量发送和接收命令减少网络往返次数,提高命令执行效率,本文就来介绍一下Redis中管道操... 目录什么是pipeline场景一:我要向Redis新增大批量的数据分批处理事务( MULTI/EXE