Remember the story of Little Match Girl? By now, you know exactly what matchsticks the little match girl has, please find out a way you can make one square by using up all those matchsticks. You should not break any stick, but you can link them up, and each matchstick must be used exactly one time.

Your input will be several matchsticks the girl has, represented with their stick length. Your output will either be true or false, to represent whether you could make one square using all the matchsticks the little match girl has.

Example 1:

Input: [1,1,2,2,2]
Output: true Explanation: You can form a square with length 2, one side of the square came two sticks with length 1.

Example 2:

Input: [3,3,3,3,4]
Output: false Explanation: You cannot find a way to form a square with all the matchsticks.

Note:

  1. The length sum of the given matchsticks is in the range of 0 to 10^9.
  2. The length of the given matchstick array will not exceed 15.

我已经服了LeetCode了,连卖火柴的小女孩也能改编成题目,还能不能愉快的玩耍了,坐等灰姑娘,丑小鸭的改编题了。好了,言归正传,这道题让我们用数组中的数字来摆出一个正方形。跟之前有道题Partition Equal Subset Sum有点像,那道题问我们能不能将一个数组分成和相等的两个子数组,而这道题实际上是让我们将一个数组分成四个和相等的子数组。我一开始尝试着用那题的解法来做,首先来判断数组之和是否是4的倍数,然后还是找能否分成和相等的两个子数组,但是在遍历的时候加上判断如果数组中某一个数字大于一条边的长度时返回false。最后我们同时检查dp数组中一条边长度位置上的值跟两倍多一条边长度位置上的值是否为true,这种方法不幸TLE了。所以只能上论坛求助各路大神了,发现了可以用优化过的递归来解,递归的方法基本上等于brute force,但是C++版本的直接递归没法通过OJ,而是要先给数组从大到小的顺序排序,这样大的数字先加,如果超过target了,就直接跳过了后面的再次调用递归的操作,效率会提高不少,所以会通过OJ。下面来看代码,我们建立一个长度为4的数组sums来保存每个边的长度和,我们希望每条边都等于target,数组总和的四分之一。然后我们遍历sums中的每条边,我们判断如果加上数组中的当前数字大于target,那么我们跳过,如果没有,我们就加上这个数字,然后对数组中下一个位置调用递归,如果返回为真,我们返回true,否则我们再从sums中对应位置将这个数字减去继续循环,参见代码如下:

解法一:

class Solution {
public:
bool makesquare(vector<int>& nums) {
if (nums.empty() || nums.size() < ) return false;
int sum = accumulate(nums.begin(), nums.end(), );
if (sum % != ) return false;
vector<int> sums(, );
sort(nums.rbegin(), nums.rend());
return helper(nums, sums, , sum / );
}
bool helper(vector<int>& nums, vector<int>& sums, int pos, int target) {
if (pos >= nums.size()) {
return sums[] == target && sums[] == target && sums[] == target;
}
for (int i = ; i < ; ++i) {
if (sums[i] + nums[pos] > target) continue;
sums[i] += nums[pos];
if (helper(nums, sums, pos + , target)) return true;
sums[i] -= nums[pos];
}
return false;
}
};

其实这题还有迭代的方法,很巧妙的利用到了位操作的特性,前面的基本求和跟判断还是一样,然后建立一个变量all,初始化为(1 << n) - 1,这是什么意思呢,all其实是一个mask,数组中有多少个数字,all就有多少个1,表示全选所有的数字,然后变量target表示一条边的长度。我们建立两个一位向量masks和validHalf,其中masks保存和target相等的几个数字位置的mask,validHalf保存某个mask是否是总和的一半。然后我们从0遍历到all,实际上就是遍历所有子数组,然后我们根据mask来计算出子数组的和,注意这里用了15,而不是32,因为题目中说了数组元素个数不会超过15个。我们算出的子数组之和如果等于一条边的长度target,我们遍历masks数组中其他等于target的子数组,如果两个mask相与不为0,说明有公用的数字,直接跳过;否则将两个mask或起来,说明我们当前选的数字之和为数组总和的一半,更新validHalf的对应位置,然后我们通过all取出所有剩下的数组,并在validHalf里查找,如果也为true,说明我们成功的找到了四条边,参见代码如下:

解法二:

class Solution {
public:
bool makesquare(vector<int>& nums) {
if (nums.empty() || nums.size() < ) return false;
int sum = accumulate(nums.begin(), nums.end(), );
if (sum % != ) return false;
int n = nums.size(), all = ( << n) - , target = sum / ;
vector<int> masks, validHalf( << n, false);
for (int i = ; i <= all; ++i) {
int curSum = ;
for (int j = ; j <= ; ++j) {
if ((i >> j) & ) curSum += nums[j];
}
if (curSum == target) {
for (int mask : masks) {
if ((mask & i) != ) continue;
int half = mask | i;
validHalf[half] = true;
if (validHalf[all ^ half]) return true;
}
masks.push_back(i);
}
}
return false;
}
};

类似题目:

Partition Equal Subset Sum

参考资料:

https://discuss.leetcode.com/topic/72107/java-dfs-solution-with-explanation

https://discuss.leetcode.com/topic/72232/c-bit-masking-dp-solution-with-detailed-comments

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Matchsticks to Square 火柴棍组成正方形的更多相关文章

  1. 473 Matchsticks to Square 火柴拼正方形

    还记得童话<卖火柴的小女孩>吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法.不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到.输入为小女孩拥有火柴的 ...

  2. Leetcode: Matchsticks to Square && Grammar: reverse an primative array

    Remember the story of Little Match Girl? By now, you know exactly what matchsticks the little match ...

  3. Leetcode之深度优先搜索(DFS)专题-473. 火柴拼正方形(Matchsticks to Square)

    Leetcode之深度优先搜索(DFS)专题-473. 火柴拼正方形(Matchsticks to Square) 深度优先搜索的解题详细介绍,点击 还记得童话<卖火柴的小女孩>吗?现在, ...

  4. [Swift]LeetCode473. 火柴拼正方形 | Matchsticks to Square

    Remember the story of Little Match Girl? By now, you know exactly what matchsticks the little match ...

  5. [Swust OJ 179]--火柴棍(找规律)

    题目链接:http://acm.swust.edu.cn/problem/0179/ Time limit(ms): 1000 Memory limit(kb): 65535   Descriptio ...

  6. BZOJ3324 : [Scoi2013]火柴棍数字

    为了使数字最大,首先要最大化其位数. 设$f[i][j][k]$表示从低到高考虑了$i$位,手头火柴棍个数为$j$,第$i$位是不是$0$时,最少移动多少根火柴. 若$f[i][0][非0]\leq ...

  7. 【LeetCode】473. Matchsticks to Square 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 回溯法 日期 题目地址:https://leetco ...

  8. LeetCode OJ 之 Maximal Square (最大的正方形)

    题目: Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and ...

  9. [LeetCode] 221. Maximal Square 最大正方形

    Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and ret ...

随机推荐

  1. 单机静默安装GI软件并创建ASM实例和ASM磁盘组

    环境:RHEL 6.4 + Oracle 11.2.0.4 需求:单机静默安装GI软件并创建ASM实例和ASM磁盘组,为后续迁移数据库文件到ASM做准备 1. 安装配置GI软件 2. 创建ASM实例 ...

  2. GDB调试命令

    1.查看源码: list [函数名][行数] 2.暂停程序 (1)设置断点: a.break + [源代码行号][源代码函数名][内存地址] b.break ... if condition   .. ...

  3. 国内maven镜像,快的飞起

    在oschina关来关去的烦恼下,终于受不了去寻找其他公共库了. 阿里云maven镜像 <mirrors> <mirror> <id>alimaven</id ...

  4. 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(二)

    我们上一篇<基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)>主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配 ...

  5. MyCat源码分析系列之——前后端验证

    更多MyCat源码分析,请戳MyCat源码分析系列 MyCat前端验证 MyCat的前端验证指的是应用连接MyCat时进行的用户验证过程,如使用MySQL客户端时,$ mysql -uroot -pr ...

  6. 前端开发之走进Vue.js

    Vue.js作为目前最热门最具前景的前端框架之一,其提供了一种帮助我们快速构建并开发前端项目的新的思维模式.本文旨在帮助大家认识Vue.js,了解Vue.js的开发流程,并进一步理解如何通过Vue.j ...

  7. 简单实用的进度条加载组件loader.js

    本文提供一个简单的方法实现一个流程的进度条加载效果,以便在页面中可以通过它来更好地反馈耗时任务的完成进度.要实现这个功能,首先要考虑怎样实现一个静态的进度条效果,类似下面这样的: 这个倒是比较简单,两 ...

  8. Rafy 框架 - 流水号插件

    Rafy 框架又添新成员:流水号插件.本文将解释 Rafy 框架中的流水插件的场景.使用方法. 场景 在开发各类数据库应用系统时,往往需要生成从一开始的流水号,有时还需要按月或者按日进行独立生成,如下 ...

  9. 【.NET MF】.NET Micro Framework USB移植

    1.开发环境 windows 7  32位 MDK 4.54 .Net Micro Framework Porting Kit 4.2(RTM QFE2) .Net Micro Framework   ...

  10. Java注解

    Java注解其实是代码里的特殊标记,使用其他工具可以对其进行处理.注解是一种元数据,起到了描述.配置的作用,生成文档,所有的注解都隐式地扩展自java.lang.annotation.Annotati ...