【记忆化搜索】【剪枝】【C++算法】1553吃掉 N 个橘子的最少天数

简介: 【记忆化搜索】【剪枝】【C++算法】1553吃掉 N 个橘子的最少天数

作者推荐

【数位dp】【动态规划】【状态压缩】【推荐】1012. 至少有 1 位重复的数字

涉及知识点

记忆化搜索 剪枝 分类讨论

LeetCode1553. 吃掉 N 个橘子的最少天数

厨房里总共有 n 个橘子,你决定每一天选择如下方式之一吃这些橘子:

吃掉一个橘子。

如果剩余橘子数 n 能被 2 整除,那么你可以吃掉 n/2 个橘子。

如果剩余橘子数 n 能被 3 整除,那么你可以吃掉 2*(n/3) 个橘子。

每天你只能从以上 3 种方案中选择一种方案。

请你返回吃掉所有 n 个橘子的最少天数。

示例 1:

输入:n = 10

输出:4

解释:你总共有 10 个橘子。

第 1 天:吃 1 个橘子,剩余橘子数 10 - 1 = 9。

第 2 天:吃 6 个橘子,剩余橘子数 9 - 2*(9/3) = 9 - 6 = 3。(9 可以被 3 整除)

第 3 天:吃 2 个橘子,剩余橘子数 3 - 2*(3/3) = 3 - 2 = 1。

第 4 天:吃掉最后 1 个橘子,剩余橘子数 1 - 1 = 0。

你需要至少 4 天吃掉 10 个橘子。

示例 2:

输入:n = 6

输出:3

解释:你总共有 6 个橘子。

第 1 天:吃 3 个橘子,剩余橘子数 6 - 6/2 = 6 - 3 = 3。(6 可以被 2 整除)

第 2 天:吃 2 个橘子,剩余橘子数 3 - 2*(3/3) = 3 - 2 = 1。(3 可以被 3 整除)

第 3 天:吃掉剩余 1 个橘子,剩余橘子数 1 - 1 = 0。

你至少需要 3 天吃掉 6 个橘子。

示例 3:

输入:n = 1

输出:1

示例 4:

输入:n = 56

输出:6

提示:

1 <= n <= 2*109

分类讨论

具有如下性质:

性质一:如果n>=3,则不可能全部是方案一,必定有方案二或方案三。当只有三个桔子时,采用方案三,只需要2天;全部全部使用方案一,则需要3天。

性质二:如 n>=4 ,且没有使用方案三或先使用方案二。则必定在n/22处采用方案二。反证法:假定某一方案,在j2个桔子时,首先使用方案二,j < n/2 假定一 。 n → \rightarrown/22 和j→ \rightarrow 0完全一样,所以只讨论:n/22 → \rightarrow j。

n/2 ⋆ \star 2 → \rightarrow n/2 → \rightarrow j ,最多用了:1+ (n/2) - j 天。式子一

n/2 ⋆ \star 2 → \rightarrow 2j → \rightarrow j 用了 n-2j+1 = n/2-j+ 1+(n/2)-j 式子二
式子二减去式子一:n/2- j 根据假定一,大于0。故:必定在n/2
2处采用方案二。

性质三:如果n >=6。且没有使用方案二或先使用方案三,则必定n/3*3出采用方案三。证明类似。

代码

核心代码

class Solution {
public:
  int minDays(int n) {
    m_data[1] = 1;
    m_data[2] = 2;
    m_data[3] = 2;
    return Rec(n);
  }
  int Rec(int n)
  {
    if (m_data.count(n))
    {
      return m_data[n];
    }
    return m_data[n] = min(Rec(n / 2 ) +n %2 +1 , Rec(n / 3)+  1 +  n %3 );
  }
  unordered_map<int, int> m_data;
};

测试用例

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()
{ 
  
  {
    Solution sln;
    vector<int> in = { 1,2,3,4,5,6,10,2000000000 };
    vector<int> ans = { 1,2,2,3,4,3 ,4,32};
    vector<int> res(in.size());
    for (int i = 0; i < in.size(); i++)
    {
      res[i] = sln.minDays(in[i]);
    }
    Assert(res, ans);
  }
}

2023年2月

class Solution {

public:

int minDays(int n) {

if( n < 3 )

{

return n ;

}

return min( n%3 + minDays(n/3) +1 ,n%2 + minDays(n/2)+1);

}

};

2023年2月 第二版

class Solution {

public:

int minDays(int n) {

if( n < 3 )

{

return n ;

}

auto it = m_mNValue.find(n);

if( m_mNValue.end() !=it )

{

return it->second;

}

return m_mNValue[n] = min( n%3 + minDays(n/3) +1 ,n%2 + minDays(n/2)+1);

}

std::unordered_map<int,int> m_mNValue;

};

2023年7月

class Solution {

public:

int minDays(int n)

{

if (n < 3)

{

return n;

}

if (m_result.count(n))

{

return m_result[n];

}

int iRet3 = (0 == n % 3) ? (minDays(n / 3) + 1) : (minDays(n / 3 * 3) + n % 3);

int iRet2 = (0 == n % 2) ? (minDays(n / 2) + 1) : (minDays(n / 2 * 2) + n % 2);

return m_result[n] = min(iRet3, iRet2);

}

std::unordered_map<int, int> m_result;

};

2023年9月

class Solution {

public:

int minDays(int n) {

if (n < 3)

{

return n;

}

if (m_mRes.count(n))

{

return m_mRes[n];

}

int iRet = min(minDays(n / 3) + 1 + n % 3, minDays(n / 2) + 1 + n % 2);

return m_mRes[n] = iRet;

}

std::unordered_map<int, int> m_mRes;

};


相关文章
|
2天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
16 2
|
11天前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
9天前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
16天前
|
算法 安全 C++
用 C++ 算法控制员工上网的软件,关键逻辑是啥?来深度解读下
在企业信息化管理中,控制员工上网的软件成为保障网络秩序与提升办公效率的关键工具。该软件基于C++语言,融合红黑树、令牌桶和滑动窗口等算法,实现网址精准过滤、流量均衡分配及异常连接监测。通过高效的数据结构与算法设计,确保企业网络资源优化配置与安全防护升级,同时尊重员工权益,助力企业数字化发展。
35 4
|
2月前
|
算法 搜索推荐 数据库
二分搜索:高效的查找算法
【10月更文挑战第29天】通过对二分搜索的深入研究和应用,我们可以不断挖掘其潜力,为各种复杂问题提供高效的解决方案。相信在未来的科技发展中,二分搜索将继续发挥着重要的作用,为我们的生活和工作带来更多的便利和创新。
61 1
|
3月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
853 0
高精度算法(加、减、乘、除,使用c++实现)
|
3月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
55 0
|
2天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
34 18
|
2天前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
30 13
|
2天前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
20 5