华为机试:叠积木

题目来源

题目描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

题目解析

  • 本题与leetcode:698. 划分为k个相等的子集本质上是一样的。
  • 本题要求我们返回最多能分成几层(也就是层高),而且要用完所有的积木
    • 用完所有的积木:表示所有的积木都要分到对应的层中
    • 我们能从参数中得到的信息是:积木的长度,通过这个长度,我们就可以算出总长度
    • 那么总长度sum和层高high有什么关系呢?
      • 如果sum % high == 0 ,那么表示可以均分,那么每一层的应该分到的长度是sum / high
      • 我们可以枚举所有的高度:2、3、4、5、…sum/2,并判断能不能满足 sum % high == 0,如果满足的话就开始尝试分配
      • 怎么分配呢?
        • 我们已经知道了应该要一共会有层:high(枚举)
        • 刚刚我们算出了每一层的的总长度score = sum / high
        • 然后开始暴力递归
  • 我们可以先计算出sum,然后我们看能不能平分成k层。
#include <utility>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

class Solution{
   std::list<std::vector<int>> snake;

   // curr为当前正在看的元素
   // used为下一个要存放到bucket中的位置
   // k表示一共需要分配多少次
   bool dfs(std::vector<int>& nums, int cur, std::vector<int>& bucket, int k, int target){
       // 结束条件:已经处理完所有球
       if (cur == nums.size()) {
           return true;
       }
       // 还有数据待分配
       // 从nums[curr]开始做选择
       for (int i = 0; i < k; i++) {  //遍历k个桶, 查看当前数可以放到哪个桶中
           // 如果当前桶和上一个桶内的元素和相等,则跳过
           // 原因:如果元素和相等,那么 nums[index] 选择上一个桶和选择当前桶可以得到的结果是一致的
           if (i > 0 && bucket[i] == bucket[i - 1]) continue;
           if (bucket[i] + nums[cur] <= target) {  // 当前元素可以放到桶中
               bucket[i] += nums[cur];
               if (dfs(nums, cur + 1,  bucket, k, target))
                   return true;
               bucket[i] -= nums[cur];
           }
       }
       return false;
   }


public:
    int process(std::vector<int> &nums){
        int sum = 0;
        for(int num : nums){
           sum += num;
        }

        int res = -1;
        std::sort(nums.begin(), nums.end());
        for (int i = 2; i <= sum / 2; ++i) {
            if(sum % i != 0){
                continue;
            }

            std::vector<int> bucket(i, 0); // 建立一个桶
            if(dfs(nums, 0, bucket, i, sum / i)){
                res = std::max(res, i);
            }
        }
        return res;
    }
};


int main(){
    std::vector<int>  num {9, 9, 9, 5, 3, 2, 2, 2, 2, 2};
     num = {3, 6, 3, 3, 3};
    Solution obj;
    cout << obj.process(num) << endl;
}

动态规划

这个问题可以转换为背包问题。

首先计算和sum,排序,选取最大的maxVal作为墙的第一层,

  • 如果 sum % maxVal == 0,代表可以这样划分,
  • 如果不可以则 maxVal += maxVal + nuns[i], 加上最小的。

可以化分的层数就为 cnt = sum / maxVal
背包容量为:sum /= cnt

#include <utility>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

class Solution{



public:
    int process(std::vector<int> &nums){

        int n = nums.size();
        if(n <= 1){
            return -1;
        }

        std::sort(nums.begin(), nums.end());
        int maxVal = nums[n - 1];
        int sum = 0;
        for(int num : nums){
           sum += num;
        }
        for (int i = 0; i < n - 1; ++i) {
            if(sum % maxVal == 0){
                break;
            }else{
                maxVal += nums[i];
            }
        }

        int cnt = sum / maxVal;
        sum /= cnt;

        std::vector<std::vector<bool>> dp(n + 1 , std::vector<bool>(sum + 1, false));

        for (int i = 0; i <= n; ++i) {
            dp[i][0] = true;
        }

        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= sum; j++){
                if(j - nums[i - 1] < 0){
                    dp[i][j] = dp[i - 1][j];
                }else{
                    dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]];
                }
            }
        }
      
        return dp[n][sum] && cnt != 1 ? cnt : -1;
    }
};


int main(){
    std::vector<int>  num {9, 9, 9, 5, 3, 2, 2, 2, 2, 2};
     num = {3, 6, 3, 3, 3};
    Solution obj;
    cout << obj.process(num) << endl;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值