C++前缀和算法的应用:摘水果 原理源码测试用例

简介: C++前缀和算法的应用:摘水果 原理源码测试用例

本文涉及的基础知识点

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

题目

在一个无限的 x 坐标轴上,有许多水果分布在其中某些位置。给你一个二维整数数组 fruits ,其中 fruits[i] = [positioni, amounti] 表示共有 amounti 个水果放置在 positioni 上。fruits 已经按 positioni 升序排列 ,每个 positioni 互不相同 。

另给你两个整数 startPos 和 k 。最初,你位于 startPos 。从任何位置,你可以选择 向左或者向右 走。在 x 轴上每移动 一个单位 ,就记作 一步 。你总共可以走 最多 k 步。你每达到一个位置,都会摘掉全部的水果,水果也将从该位置消失(不会再生)。

返回你可以摘到水果的 最大总数 。

示例 1:

输入:fruits = [[2,8],[6,3],[8,6]], startPos = 5, k = 4

输出:9

解释:

最佳路线为:

  • 向右移动到位置 6 ,摘到 3 个水果
  • 向右移动到位置 8 ,摘到 6 个水果
    移动 3 步,共摘到 3 + 6 = 9 个水果
    示例 2:
    输入:fruits = [[0,9],[4,1],[5,7],[6,2],[7,4],[10,9]], startPos = 5, k = 4
    输出:14
    解释:
    可以移动最多 k = 4 步,所以无法到达位置 0 和位置 10 。
    最佳路线为:
  • 在初始位置 5 ,摘到 7 个水果
  • 向左移动到位置 4 ,摘到 1 个水果
  • 向右移动到位置 6 ,摘到 2 个水果
  • 向右移动到位置 7 ,摘到 4 个水果
    移动 1 + 3 = 4 步,共摘到 7 + 1 + 2 + 4 = 14 个水果
    示例 3:
    输入:fruits = [[0,3],[6,4],[8,5]], startPos = 3, k = 2
    输出:0
    解释:
    最多可以移动 k = 2 步,无法到达任一有水果的地方

参数范围

1 <= fruits.length <= 105

fruits[i].length == 2

0 <= startPos, positioni <= 2 * 105

对于任意 i > 0 ,positioni-1 < positioni 均成立(下标从 0 开始计数)

1 <= amounti <= 104

0 <= k <= 2 * 105

分析

原理

只需要左移(右移)一次。假定左移了两次,分别移动了x1,x2,假定x1<x2。则不移动x1,水果不会少。

分四种情况:

一,左移到底。

二,先左移,后右移。

三,右移到底。

四,先右移,再左移。

一是四的特殊请,三是二的特殊情况。

步骤

一,先获取前缀和。

二,枚举左移。右移为0或负数,忽视,因为劣于左移到底。k为0是,此条不符合。

三,枚举右移。

注意

坐标无限,但前缀和有限[0,iMaxPos]。

左移后的坐标 可能小于0
左移后的坐标 ** 可能大于iMax**
右移后的坐标 可能大于iMax
k为0时要左特殊处理。

变量解释

vNum 各坐标水果数量
vSum /vSum[i]记录[0,i)草莓的总数量
iMoveLeft 左移距离
iMoveRight 右移距离
left 移动到的最左坐标
right 移动到最右坐标

代码

核心代码

class Solution {
public:
int maxTotalFruits(vector<vector>& fruits, int startPos, int k) {
const int iMaxPos = fruits.back()[0];
vector vNum(iMaxPos + 1);
for (const auto&v : fruits)
{
vNum[v[0]] = v[1];
}
vector vSum = { 0 };//vSum[i]记录[0,i)草莓的总数量
for (int i =0; i <= iMaxPos; i++)
{
vSum.emplace_back(vSum.back() + vNum[i]);
}
int iRet = 0;
  for (int iMoveLeft = 0; iMoveLeft <= k / 2; iMoveLeft++)
  {//先左后右
    const int iMoveRight = k - iMoveLeft * 2;
    if (iMoveRight < 0)
    {
      continue;
    }
    const int left = max(0, startPos - iMoveLeft);
    if (left > iMaxPos)
    {
      continue;
    }
    const int right = min(iMaxPos, startPos + iMoveRight);
    //可收集[left,right+1)的草莓
    const int cur = vSum[right + 1] - vSum[left];
    iRet = max(iRet, cur);
  }
  for (int iMoveRight = 0; iMoveRight <= k / 2; iMoveRight++)
  {//先左后右
    const int iMoveLeft = k - iMoveRight * 2;
    if (iMoveLeft < 0)
    {
      continue;
    }
    const int left = max(0, startPos - iMoveLeft);
    if (left > iMaxPos)
    {
      continue;
    }
    const int right = min(iMaxPos, startPos + iMoveRight);
    //可收集[left,right+1)的草莓
    const int cur = vSum[right + 1] - vSum[left];
    iRet = max(iRet, cur);
  }
  return iRet;
}

};

测试用例

template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
assert(v1[i] == v2[i]);
}
}
template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}
int main()
{
Solution slu;
vector<vector> fruits;
int startPos = 0;
int k = 0;
int res;
fruits = {{2, 8}, {6, 3}, {8, 6}};
startPos =5 ;
k =4 ;
res = slu.maxTotalFruits(fruits, startPos, k);
Assert(9, res);
fruits = {{0, 9}, {4, 1}, {5, 7}, {6, 2}, {7, 4}, {10, 9}};
startPos = 5;
k = 4;
res = slu.maxTotalFruits(fruits, startPos, k);
Assert(14, res);
fruits = { {0,10000} };
startPos = 20000;
k = 20000;
res = slu.maxTotalFruits(fruits, startPos, k);
Assert(10000, res);
fruits = { {20000,10000} };
startPos = 20000;
k = 0;
res = slu.maxTotalFruits(fruits, startPos, k);
Assert(10000, res);
//CConsole::Out(res);

}

2023年3月旧代码

class Solution {
public:
int maxTotalFruits(vector<vector>& fruits, int startPos, int k) {
m_c = fruits.size();
int iMaxLeftIndex = std::lower_bound(fruits.begin(), fruits.end(),startPos, [](const vector& v, int i)
{
return v[0] < i;
}) - fruits.begin() - 1;
std::map<int, int> mLeftMoveNum;
for (int i = iMaxLeftIndex ; (i >= 0) && (startPos - fruits[i][0] <= k); i–)
{
const int iLeftMove = startPos - fruits[i][0];
mLeftMoveNum[iLeftMove] = fruits[i][1] + (mLeftMoveNum.empty() ? 0 : mLeftMoveNum.rbegin()->second);
}
int iMinRightIndex = iMaxLeftIndex + 1;
int iRet = 0;
if ((iMinRightIndex < m_c) && (fruits[iMinRightIndex][0] == startPos))
{
iRet += fruits[iMinRightIndex][1];
iMinRightIndex++;
}
std::map<int, int> mRightMoveNum;
for (int i = iMinRightIndex; (i < m_c) && (fruits[i][0] - startPos <= k); i++)
{
const int iRightMove = fruits[i][0] - startPos;
mRightMoveNum[iRightMove] = fruits[i][1] + (mRightMoveNum.empty() ? 0 : mRightMoveNum.rbegin()->second);
}
int iMaxExcludeStart = 0;
   for (int left = 0; left <= k / 2; left++)
   {
     const int right = k - left * 2;
     int iCur = 0;
     {
       auto itLeft = mLeftMoveNum.upper_bound(left);
       if (mLeftMoveNum.begin() != itLeft)
       {
         iCur += (--itLeft)->second;
       }
     }
     {
       auto itRight = mRightMoveNum.upper_bound(right);
       if (mRightMoveNum.begin() != itRight)
       {
         iCur += (--itRight)->second;
       }
     }
     iMaxExcludeStart = max(iMaxExcludeStart, iCur);
   }
   for (int right = 0; right <= k / 2; right++)
   {
     const int left = k - right * 2;
     int iCur = 0;
     {
       auto itLeft = mLeftMoveNum.upper_bound(left);
       if (mLeftMoveNum.begin() != itLeft)
       {
         iCur += (--itLeft)->second;
       }
     }
     {
       auto itRight = mRightMoveNum.upper_bound(right);
       if (mRightMoveNum.begin() != itRight)
       {
         iCur += (--itRight)->second;
       }
     }
     iMaxExcludeStart = max(iMaxExcludeStart, iCur);
   }
   iRet += iMaxExcludeStart;
   return iRet;
 }
 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

相关文章
|
5天前
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
2月前
|
Java 测试技术 数据安全/隐私保护
软件测试中的自动化策略与工具应用
在软件开发的快速迭代中,自动化测试以其高效、稳定的特点成为了质量保证的重要手段。本文将深入探讨自动化测试的核心概念、常见工具的应用,以及如何设计有效的自动化测试策略,旨在为读者提供一套完整的自动化测试解决方案,帮助团队提升测试效率和软件质量。
|
6天前
|
编解码 缓存 Prometheus
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
本期内容为「ximagine」频道《显示器测试流程》的规范及标准,我们主要使用Calman、DisplayCAL、i1Profiler等软件及CA410、Spyder X、i1Pro 2等设备,是我们目前制作内容数据的重要来源,我们深知所做的仍是比较表面的活儿,和工程师、科研人员相比有着不小的差距,测试并不复杂,但是相当繁琐,收集整理测试无不花费大量时间精力,内容不完善或者有错误的地方,希望大佬指出我们好改进!
61 16
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
|
24天前
|
搜索推荐 测试技术 API
探秘电商API:从测试到应用的深度解析与实战指南
电商API是电子商务背后的隐形引擎,支撑着从商品搜索、购物车更新到支付处理等各个环节的顺畅运行。它通过定义良好的接口,实现不同系统间的数据交互与功能集成,确保订单、库存和物流等信息的实时同步。RESTful、GraphQL和WebSocket等类型的API各自适用于不同的应用场景,满足多样化的需求。在测试方面,使用Postman、SoapUI和jMeter等工具进行全面的功能、性能和安全测试,确保API的稳定性和可靠性。未来,随着人工智能、大数据和物联网技术的发展,电商API将进一步智能化和标准化,为用户提供更个性化的购物体验,并推动电商行业的持续创新与进步。
56 4
|
2月前
|
编译器 C语言 C++
【c++丨STL】list模拟实现(附源码)
本文介绍了如何模拟实现C++中的`list`容器。`list`底层采用双向带头循环链表结构,相较于`vector`和`string`更为复杂。文章首先回顾了`list`的基本结构和常用接口,然后详细讲解了节点、迭代器及容器的实现过程。 最终,通过这些步骤,我们成功模拟实现了`list`容器的功能。文章最后提供了完整的代码实现,并简要总结了实现过程中的关键点。 如果你对双向链表或`list`的底层实现感兴趣,建议先掌握相关基础知识后再阅读本文,以便更好地理解内容。
47 1
|
3月前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
144 5
|
3月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
99 1
|
3月前
|
Java 测试技术 API
软件测试中的自动化测试框架选择与应用##
在快速迭代的软件开发周期中,选择合适的自动化测试框架对于提高软件质量和开发效率至关重要。本文探讨了当前流行的几种自动化测试框架的特点和适用场景,旨在为软件开发团队提供决策依据。 ##
|
3月前
|
机器学习/深度学习 人工智能 安全
探索AI在软件工程中的最新应用:自动化测试与代码审查
探索AI在软件工程中的最新应用:自动化测试与代码审查
|
2天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。

热门文章

最新文章