C++二分算法:最多可以参加的会议数目 II

简介: C++二分算法:最多可以参加的会议数目 II

题目

给你一个 events 数组,其中 events[i] = [startDayi, endDayi, valuei] ,表示第 i 个会议在 startDayi 天开始,第 endDayi 天结束,如果你参加这个会议,你能得到价值 valuei 。同时给你一个整数 k 表示你能参加的最多会议数目。

你同一时间只能参加一个会议。如果你选择参加某个会议,那么你必须 完整 地参加完这个会议。会议结束日期是包含在会议内的,也就是说你不能同时参加一个开始日期与另一个结束日期相同的两个会议。

请你返回能得到的会议价值 最大和 。

示例 1:

输入:events = [[1,2,4],[3,4,3],[2,3,1]], k = 2

输出:7

解释:选择绿色的活动会议 0 和 1,得到总价值和为 4 + 3 = 7 。

示例 2:

输入:events = [[1,2,4],[3,4,3],[2,3,10]], k = 2

输出:10

解释:参加会议 2 ,得到价值和为 10 。

你没法再参加别的会议了,因为跟会议 2 有重叠。你 不 需要参加满 k 个会议。

示例 3:

输入:events = [[1,1,1],[2,2,2],[3,3,3],[4,4,4]], k = 3

输出:9

解释:尽管会议互不重叠,你只能参加 3 个会议,所以选择价值最大的 3 个会议。

**参数范围:

1 <= k <= events.length

1 <= k * events.length <= 106

1 <= startDayi <= endDayi <= 109

1 <= valuei <= 106

分析

时间复杂度

时间复杂度O(knlogn),两层循环。第一层循环循环k-1次,第二层循环循环n次。循环内部查找、插入、删除O(logn)。

变量解释

mPre 记录的上一轮的完成情况,dp是当前轮的完成情况。键对应的是:结束时间,值对应的是:最大会议价值。如果key0 <= key1且value0 >= value1,那么key0会淘汰key1。能选取key1,一定能选取key0,而value0大于等于value1。淘汰后,值保持升序。键小的淘汰键大的。

代码

核心代码

template<class _Kty,class _Ty,bool bValueDdes,bool bOutSmallKey> 
class COrderValueMap 
{
public:
  void Add (_Kty iValue, _Ty iNum)
  {
    if (bOutSmallKey)
    {
      if (bValueDdes)
      {
        AddOutSmall(iValue, iNum, std::less_equal<_Ty>(), std::greater_equal<_Ty>());
      }
      else
      {
      }
    }
    else 
    {
      if (bValueDdes)
      {
        AddNotOutSmall(iValue, iNum, std::greater_equal<_Ty>(), std::less_equal<_Ty>());
      }
      else
      {
        AddNotOutSmall(iValue, iNum, std::less_equal<_Ty>(), std::greater_equal<_Ty>());
      }
    }
  };
  template<class _Pr1, class _Pr2>
  void AddOutSmall(_Kty key, _Ty value, _Pr1 pr1, _Pr2 pr2)
  {
    auto it = m_map.lower_bound(key);
    if ((m_map.end() != it) && pr1(it->second, value))
    {
      return;//被旧值淘汰
    }
    auto ij = it;
    while (it != m_map.begin())
    {
      --it;
      if (pr2(it->second, value))
      {
        it = m_map.erase(it);
      }
    }
    m_map[key] = value;
  }
  template<class _Pr1, class _Pr2>
  void AddNotOutSmall(_Kty key, _Ty value, _Pr1 pr1,_Pr2 pr2 )
  {
    auto it = m_map.upper_bound(key);
    if ((m_map.begin() != it) && pr1(std::prev(it)->second, value))
    {
      return;//被淘汰
    }
    auto ij = it;
    for (; (m_map.end() != ij) && pr2(ij->second, value); ++ij);
    m_map.erase(it, ij);
    m_map[key] = value;
  };
  std::map<_Kty, _Ty> m_map;
};
class Solution {
public:
  int maxValue(vector<vector<int>>& events, int k) {
    COrderValueMap<int, int, true, false> mPre;
    for (const auto& v : events)
    {
      mPre.Add(v[1], v[2]);
    }
    while (--k)
    {
      COrderValueMap<int, int, true, false> dp;
      for (const auto& v : events)
      {
        auto it = mPre.m_map.lower_bound(v[0]);
        int iNewValue = v[2];
        if (mPre.m_map.begin() != it)
        {
          iNewValue += std::prev(it)->second;
        }
        dp.Add(v[1], iNewValue);
      }
      dp.m_map.swap(mPre.m_map);
    }
    return mPre.m_map.rbegin()->second;
  } 
};

测试用例

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<vector<int>> events;
  int k;
  int res;
  {
    Solution slu;
    events = { {1,2,4},{3,4,3},{2,3,1} };
    k = 2;
    res = slu.maxValue(events, k);
    Assert(res,7 );
  }
  {
    Solution slu;
    events = { {1,2,4},{3,4,3},{2,3,10} };
    k = 2;
    res = slu.maxValue(events, k);
    Assert(res, 10);
  }
  {
    Solution slu;
    events = { {1,1,1},{2,2,2},{3,3,3},{4,4,4} };
    k = 3;
    res = slu.maxValue(events, k);
    Assert(res, 9);
  }
  //CConsole::Out(res);
}

优化版:第一轮不特殊处理

class Solution {
public:
int maxValue(vector& events, int k) {
COrderValueMap mPre;
mPre.Add(0, 0);
while (k–)
{
COrderValueMap dp;
for (const auto& v : events)
{
auto it = mPre.m_map.lower_bound(v[0]);
int iNewValue = v[2];
if (mPre.m_map.begin() != it)
{
iNewValue += std::prev(it)->second;
}
dp.Add(v[1], iNewValue);
}
dp.m_map.swap(mPre.m_map);
}
return mPre.m_map.rbegin()->second;
}
};

2023年2月旧代码

class Solution {
public:
int maxValue(vector& events, int k) {
//dp[i] 已经完成i次会议后的最大值
vector vFinish(k + 1, -1);
vFinish[0] = 0;
std::map mDoing;
std::sort(events.begin(), events.end(), [](const vector& v1, const vector& v2)
{
return v1[0] < v2[0];
});
for (const auto& v : events)
{
while (mDoing.size() && mDoing.begin()->first < v[0])
{
vector& vDoing = mDoing.begin()->second;
for (int iK = 0; iK <= k; iK++)
{
vFinish[iK] = max(vDoing[iK], vFinish[iK]);
}
mDoing.erase(mDoing.begin());
}
vector& vDoing = mDoing[v[1]];
if (0 == vDoing.size())
{
vDoing.resize(k + 1, -1);
}
for (int iK = 0; iK <= k; iK++)
{
vDoing[iK] = max(vDoing[iK], vFinish[iK]);
if (iK > 0)
{
vDoing[iK] = max(vDoing[iK], vFinish[iK-1] + v[2] );
}
}
}
while (mDoing.size() )
{
vector& vDoing = mDoing.begin()->second;
for (int iK = 0; iK <= k; iK++)
{
vFinish[iK] = max(vDoing[iK], vFinish[iK]);
}
mDoing.erase(mDoing.begin());
}
return *std::max_element(vFinish.begin(), vFinish.end());
}
};

2023年9月旧代码

class Solution {
public:
int maxValue(vector& events, int k) {
m_c = events.size();
vector indexs(m_c);
iota(indexs.begin(), indexs.end(), 0);
sort(indexs.begin(), indexs.end(), [&events](const int& i1, const int& i2)
{
return events[i1][0] < events[i2][0];
});
std::map mEndValue;
mEndValue[-1] = 0;
for (int iK = 0; iK < k; iK++)
{
std::map dp;
for (const auto& i : indexs)
{
auto it = mEndValue.lower_bound(events[i][0]);
const int iPre = (it == mEndValue.begin()) ? 0 : std::prev(it)->second;
const int iNew = iPre + events[i][2];
auto ij = dp.upper_bound(events[i][1]);
if ((ij != dp.begin()) && (std::prev(ij)->second >= iNew))
{
continue;//前面的数值大,再增意义
}
ij = dp.lower_bound(events[i][1]);
auto tmp = ij;
for (; (tmp != dp.end()) && (tmp->second <= iNew); ++tmp);
dp.erase(ij, tmp);
dp[events[i][1]] = iNew;
}
dp.swap(mEndValue);
}
int iMax = 0;
for (const auto& it : mEndValue)
{
iMax = max(iMax, it.second);
}
return iMax;
}
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


相关文章
|
3天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
17 2
|
11天前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
9天前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
16天前
|
算法 安全 C++
用 C++ 算法控制员工上网的软件,关键逻辑是啥?来深度解读下
在企业信息化管理中,控制员工上网的软件成为保障网络秩序与提升办公效率的关键工具。该软件基于C++语言,融合红黑树、令牌桶和滑动窗口等算法,实现网址精准过滤、流量均衡分配及异常连接监测。通过高效的数据结构与算法设计,确保企业网络资源优化配置与安全防护升级,同时尊重员工权益,助力企业数字化发展。
35 4
|
3月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
855 0
高精度算法(加、减、乘、除,使用c++实现)
|
3月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
56 0
|
3月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
5天前
|
算法 数据安全/隐私保护
室内障碍物射线追踪算法matlab模拟仿真
### 简介 本项目展示了室内障碍物射线追踪算法在无线通信中的应用。通过Matlab 2022a实现,包含完整程序运行效果(无水印),支持增加发射点和室内墙壁设置。核心代码配有详细中文注释及操作视频。该算法基于几何光学原理,模拟信号在复杂室内环境中的传播路径与强度,涵盖场景建模、射线发射、传播及接收点场强计算等步骤,为无线网络规划提供重要依据。
|
6天前
|
机器学习/深度学习 数据采集 算法
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目基于MATLAB2022a实现时间序列预测,采用CNN-GRU-SAM网络结构。卷积层提取局部特征,GRU层处理长期依赖,自注意力机制捕捉全局特征。完整代码含中文注释和操作视频,运行效果无水印展示。算法通过数据归一化、种群初始化、适应度计算、个体更新等步骤优化网络参数,最终输出预测结果。适用于金融市场、气象预报等领域。
基于GA遗传优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
|
6天前
|
算法
基于龙格库塔算法的锅炉单相受热管建模与matlab数值仿真
本设计基于龙格库塔算法对锅炉单相受热管进行建模与MATLAB数值仿真,简化为喷水减温器和末级过热器组合,考虑均匀传热及静态烟气处理。使用MATLAB2022A版本运行,展示自编与内置四阶龙格库塔法的精度对比及误差分析。模型涉及热传递和流体动力学原理,适用于优化锅炉效率。