华为机试:叠积木

题目来源

  • 华为机试:叠积木

题目描述

华为机试:叠积木_第1张图片
华为机试:叠积木_第2张图片

华为机试:叠积木_第3张图片

题目解析

  • 本题与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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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;
}

你可能感兴趣的:(算法与数据结构,华为,深度优先,leetcode)