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. MySQL用户管理

    主要总结MySQL进行用户管理的基本实现,包含MySQL登录,添加用户,删除用户,为用户分配权限,移除某用户的权限,修改密码,查看权限等基本操作,所有命令均亲测实现.本博文是本人的劳动成果所得,在博客 ...

  2. 如果你也会C#,那不妨了解下F#(4):了解函数及常用函数

    函数式编程其实就是按照数学上的函数运算思想来实现计算机上的运算.虽然我们不需要深入了解数学函数的知识,但应该清楚函数式编程的基础是来自于数学. 例如数学函数\(f(x) = x^2+x\),并没有指定 ...

  3. EntityFramework 事务处理

    默认情况下,当EF调用SaveChanges()时,会把生成的所有SQL命令“包”到一个“事务(transaction)”中,只要有一个数据更新操作失败,整个事务将回滚. 在多数情况下,如果你总在数据 ...

  4. JSON扩展类——JsonHelper

    1.引用Newtonsoft.Json库(JSON.NET). 2.复制粘贴JsonHelper吧. 源代码: using System; using System.Collections.Gener ...

  5. WebApi安全性 使用TOKEN+签名验证

    首先问大家一个问题,你在写开放的API接口时是如何保证数据的安全性的?先来看看有哪些安全性问题在开放的api接口中,我们通过http Post或者Get方式请求服务器的时候,会面临着许多的安全性问题, ...

  6. JDBC_part3_批处理_事务_元数据

    本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! JDBC_day03 String a = " ...

  7. java socket编程(li)

    一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以 ...

  8. GJM : Unity3D HIAR -【 快速入门 】 六、导出 iOS 工程

    导出 iOS 工程 在开始之前,请务必先保存您的工程.由于 Unity 无法直接生成 ipa 文件,您需要先导出 iOS 工程文件,然后通过 Xcode 编译生成. Step 1. 选择平台 在 Un ...

  9. 浅谈Hybrid技术的设计与实现

    前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 随着移动浪潮的兴起,各种APP层出不穷,极速的业务扩展提升了团队对开发 ...

  10. CentOS7安装docker

    1. 查看系统版本 $ cat /etc/redhat-release   2. 安装docker $  yum install docker 3.检查安装是否成功$ docker version 若 ...