【贪心数学推理困难题】1739. 放置盒子题解

182 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天,点击查看活动详情

✨欢迎关注🖱点赞🎀收藏⭐留言✒

🔮本文由京与旧铺原创,csdn首发!

😘系列专栏:算法学习

💻首发时间:🎞2022年12月27日🎠

🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦

🎧作者是一个新人,在很多方面还做的不好,欢迎大佬指正,一起学习哦,冲冲冲


⭐️1739. 放置盒子⭐️

1739. 放置盒子

🔐题目详情

难度困难

有一个立方体房间,其长度、宽度和高度都等于 n 个单位。请你在房间里放置 n 个盒子,每个盒子都是一个单位边长的立方体。放置规则如下:

  • 你可以把盒子放在地板上的任何地方。
  • 如果盒子 x 需要放置在盒子 y 的顶部,那么盒子 y 竖直的四个侧面都 必须 与另一个盒子或墙相邻。

给你一个整数 n ,返回接触地面的盒子的 最少 可能数量*。*

示例 1:

img

输入:n = 3
输出:3
解释:上图是 3 个盒子的摆放位置。
这些盒子放在房间的一角,对应左侧位置。

示例 2:

img

输入:n = 4
输出:3
解释:上图是 3 个盒子的摆放位置。
这些盒子放在房间的一角,对应左侧位置。

示例 3:

img

输入:n = 10
输出:6
解释:上图是 10 个盒子的摆放位置。
这些盒子放在房间的一角,对应后方位置。

提示:

  • 1 <= n <= 109

💡解题思路

解题思路: 贪心思想+数学推理题

想要占地板数最少,那么需要靠墙角进行方块的放置,因为墙角天然提供了两个侧面的消耗,这是这道题贪心的一个点吧,并且以类阶梯放置时,所占地面的方块数最少,下面我们来进行找规律。

地面上盒子数为11时,最多可以放11个盒子。 1

地面上盒子数为22时,最多可以放22个盒子。

2 地面上盒子数为33时,最多可以放44个盒子,不妨将这种放置情况称为完整的阶梯堆,以下简称阶梯堆。

3 地面上盒子数为44时,最多可以放55个盒子,相比于上一个阶梯堆,多了11个地面盒子,多了11个盒子上限。 4

地面上盒子数为55时,最多可以放77个盒子,相比于上一个阶梯堆,多了22个地面盒子,多了1+21+2个盒子上限。 5 地面上盒子数为66时,最多可以放1010个盒子,相比于上一个阶梯堆,多了33个地面盒子,多了1+2+31+2+3个盒子上限,形成了一个完整放置的阶梯堆。 6 地面上盒子数为77时,最多可以放1111个盒子,相比于上一个阶梯堆,多了11个地面盒子,多了11个盒子上限。 7

地面上盒子数为88时,最多可以放1313个盒子,相比于上一个阶梯堆,多了22个地面盒子,多了1+21+2个盒子上限。 8

地面上盒子数为99时,最多可以放1616个盒子,相比于上一个阶梯堆,多了33个地面盒子,多了1+2+31+2+3个盒子上限。 9 地面上盒子数为1010时,最多可以放1616个盒子,相比于上一个阶梯堆,多了44个地面盒子,多了1+2+3+41+2+3+4个盒子上限,并且形成了一个新的阶梯堆。 10

通过这些举例,我们可以看出一些规律,当地面放置的盒子数为111+21+21+2+31+2+3,...,1+2+3+...+i1+2+3+...+i时,最多放置的盒子堆是一个阶梯堆。

地面盒子为1+2+3+...+i1+2+3+...+i时,即i×(1+i)2\frac{i\times(1+i)}{2}(等差数列求和),所对应盒子的上限为maxNmaxN(裂项相消):

1+(1+2)+(1+2+3)+...+(1+2+3+...+i)=i=1ii×(1+i)21+(1+2)+(1+2+3)+...+(1+2+3+...+i)=\sum_{i=1}^{i}{\frac{i\times(1+i)}{2}}

因为从顶端往下数,每层的盒子数为111+21+21+2+31+2+3,...,1+2+3+...+i1+2+3+...+i

利用裂项相消计算得:

i=1ii×(1+i)2=i=1i(i×(1+i)2×[(i+2)(i1)]3)=i=1i(i(i+1)(i+2)6(i1)i(i+1)6)=16i=1i[i(i+1)(i+2)(i1)i(i+1)]=[(1×2×3)(0×1×2)+(2×3×4)(1×2×3)+...+i(i+1)(i+2)(i1)i(i+1)]=16[i(i+1)(i+2)(0×1×2)]=i(i+1)(i+2)6\begin{aligned} \sum_{i=1}^{i}{\frac{i\times(1+i)}{2}}&=\sum_{i=1}^{i}({\frac{i\times(1+i)}{2}}\times\frac{[(i+2)-(i-1)]}{3})\\ &=\sum_{i=1}^{i}(\frac{i(i+1)(i+2)}{6}-\frac{(i-1)i(i+1)}{6})\\ &=\frac{1}{6}\sum_{i=1}^{i}[i(i+1)(i+2)-(i-1)i(i+1)]\\ &=[(1\times2\times3)-(0\times1\times2)+(2\times3\times4)-(1\times2\times3)+...+i(i+1)(i+2)-(i-1)i(i+1)]\\ &=\frac{1}{6}[i(i+1)(i+2)-(0\times1\times2)]\\ &=\frac{i(i+1)(i+2)}{6}\\ \end{aligned}

最终maxN=i(i+1)(i+2)6maxN=\frac{i(i+1)(i+2)}{6}

根据变化规律,在阶梯堆基础上添加地面盒子数jj个,盒子上限会增加1+2+3+...+j=j×(1+j)21+2+3+...+j=\frac{j\times(1+j)}{2}。【不妨称作添加规律】

对于本题我们可以算出最大阶梯堆的地面盒子数量不妨设为x=1+2+...+k=k×(1+k)2x=1+2+...+k=\frac{k\times(1+k)}{2},然后再将剩余的盒子以以上【添加规律】模拟计数得出yy,即可的最终所占的地面盒子数ans=x+yans=x+y

🔑源代码

Java代码1:

class Solution {
    public int minimumBoxes(int n) {
        int maxN = 0;
        int ans = 0;
        int k = 1;
        while (k * (1 + k) / 2 + maxN <= n) {
            maxN += k * (1 + k) / 2;
            k++;
        }

        //k多记了1
        k--;
        //x
        ans = k * (1 + k) / 2;
        k = 1;
        //基于阶梯堆,每增加一块地面盒子,上限增加k(k从1递增)
        while (maxN < n) {
            maxN += k;
            ans++;
            k++;
        }
        return ans;
    }
}

Java代码2:

class Solution {
    public int minimumBoxes(int n) {
        int maxN = 1;
        int ans = 0;
        int k = 1;
        while (maxN <= n) {
            k++;
            maxN = (int) ((long) k * (1 + k) * (2 + k) / 6);
        }

        //k多记了1
        k--;
        maxN = (int) ((long) k * (1 + k) * (2 + k) / 6);
        //x
        ans = k * (1 + k) / 2;
        k = 1;
        //基于阶梯堆,每增加一块地面盒子,上限增加k(k从1递增)
        while (maxN < n) {
            maxN += k;
            ans++;
            k++;
        }
        return ans;
    }
}

C++代码1:

class Solution {
public:
    int minimumBoxes(int n) {
        int ans = 0;
        int k = 1;
        int maxN = 0;
        while (maxN + k * (1 + k) / 2 <= n) 
        {
            maxN += k * (1 + k) / 2;
            k++;
        }
        //k多加1
        --k;

        ans = k * (1 + k) / 2;
        k = 1;
        while (maxN < n)
        {
            ans++;
            maxN += k;
            k++;
        }
        return ans;
    }
};

C++代码2:

class Solution {
public:
    int minimumBoxes(int n) {
        int ans = 0;
        int k = 1;
        int maxN = 1;
        while (maxN <= n) 
        {
            k++;
            maxN = (int) ((long) k * (k + 1) * (k + 2) / 6);
        }
        //k多加1
        --k;
        maxN = (int) ((long) k * (k + 1) * (k + 2) / 6);
        ans = k * (1 + k) / 2;
        k = 1;
        while (maxN < n)
        {
            ans++;
            maxN += k;
            k++;
        }
        return ans;
    }
};

C语言代码1:

int minimumBoxes(int n){
    int ans = 0;
    int k = 1;
    int maxN = 0;
    while (maxN + k * (1 + k) / 2 <= n) 
    {
        maxN += k * (1 + k) / 2;
        k++;
    }
    //k多加1
    --k;

    ans = k * (1 + k) / 2;
    k = 1;
    while (maxN < n) 
    {
        ans++;
        maxN += k;
        k++;
    }
    return ans;
}

C语言代码2:

int minimumBoxes(int n){
    int ans = 0;
    int k = 1;
    int maxN = 1;
    while (maxN <= n) 
    {
        k++;
        maxN = (int) ((long) k * (k + 1) * (k + 2) / 6);
    }
    //k多加1
    --k;
    maxN = (int) ((long) k * (k + 1) * (k + 2) / 6);
    ans = k * (1 + k) / 2;
    k = 1;
    while (maxN < n) 
    {
        ans++;
        maxN += k;
        k++;
    }
    return ans;
}

🌱总结

本题主要有两个难点,一个是贪心思维,知道从墙角下手,第二个就是数学规律推理,找出盒子变化规律。


参考资料: leetcode.cn/problems/bu…