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


相关文章
|
1月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
419 0
高精度算法(加、减、乘、除,使用c++实现)
|
1月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
22 0
|
1月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
1月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
1月前
|
机器学习/深度学习 人工智能 算法
【算法】最长公共子序列(C/C++)
【算法】最长公共子序列(C/C++)
|
1月前
|
人工智能 算法 BI
一篇带你速通差分算法(C/C++)
一篇带你速通差分算法(C/C++)
|
1月前
|
人工智能 算法 C++
一篇带你速通前缀和算法(C/C++)
一篇带你速通前缀和算法(C/C++)
|
1月前
|
存储 算法 C++
弗洛伊德(Floyd)算法(C/C++)
弗洛伊德(Floyd)算法(C/C++)
|
25天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
10天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。