(search + backtracking + pruning) leetcode medium 473. Matches and squares

topic

You will get an integer array matchsticks, where matchsticks[i] is the length of the i-th matchstick. You will use all the matchsticks to form a square. You can't break any of the matchsticks, but you can connect them together, and each matchstick must be used once.

Returns true if you can make the square, false otherwise.

Example 1:

Input: matchsticks = [1,1,2,2,2]
Output: true
Explanation: It can form a square with side length 2 and two matches on each side.

Example 2:
Input: matchsticks = [3,3,3,3,4]
Output: false
Explanation: You cannot make a square with all the matches.

hint:

1 <= matchsticks.length <= 15
1 <= matchsticks[i] <= 108

Source: LeetCode
Link: https://leetcode-cn.com/problems/matchsticks-to-square The
copyright belongs to LeetCode.com. For commercial reprints, please contact the official authorization, and for non-commercial reprints, please indicate the source.

analyze

Seeing the scale, we can directly think of the violent method, n<=15, then we directly think of the most violent method, we can try to put a match on the four sides, and so on, one match has four choices, the largest 15 matches are 4 to the 15th power, 2 to the 30th power, and 10 to the 9th power. Obviously, it will time out. At this time, we will judge how to prune
. 1. If the given match is less than 4, it must not work
. 2. If The total length of the given matches cannot be divisible by 4. It must not work
. 3. The maximum length of an edge should be a quarter of the total length, and it must not exceed a quarter.
Optimization
1. We can sort the given array, the larger Put it in the front
because there are more combinations of small numbers, and fewer combinations of large numbers, so there will be less backtracking

After these few optimizations, it is almost the same. If you still feel that it is not possible, you can add memoization. This
problem can be imagined as putting matches into four buckets, traversing each bucket and putting the match. It is not enough, if not, backtracking traversal Other buckets, until all the buckets are traversed, if it doesn't work, it can't form a square

code section

1. Initialization

First judge that if the number of matches in the given array is less than four, return false directly, initialize a sum to calculate the total length of the matches, judge that if the total length cannot be divisible by 4, return false directly, and then sort from large to small

		if(matchsticks.size()<4)
			return false;
		 int sum=0;
		 for(int i=0;i<matchsticks.size();i++)
		 	sum+=matchsticks[i];
		if(sum%4!=0)
			return false;
		sort(matchsticks.rbegin(),matchsticks.rend());
2. Search section

First of all, the function of our search is to find out whether the current match is placed in the current bucket, and whether the subsequent bucket can meet the final conditions to
analyze what can be done now, and directly list four situations in the for loop. There are four choices for the current match. It can be put into four buckets and pruned: after the matches are put into the bucket, the total length of the matches in the bucket cannot exceed a quarter of the sum, and it is judged whether the subsequent buckets can meet the final conditions after the current matches are put into the bucket. , this matter can be handled by recursion, because we set the function of this function to be this, if not,
when the recursion exits, we should return, that is, recursion until all matches are put out, this When it is judged that if all four buckets meet the conditions, it means that they can be made into a square.

	bool generate(int i,vector<int> &matchsticks,int target,int bucket[])
	{
    
    
		//出口 
		if(i>=matchsticks.size())
		{
    
    
			return bucket[0]==target&&bucket[1]==target&&
			bucket[2]==target&&bucket[3]==target;
		}
		//现在能做的事情
		for(int j=0;j<4;j++)	//分别向四个桶里装火柴 
		{
    
    
			if(bucket[j]+matchsticks[i]>target)
				continue;
			bucket[j]+=matchsticks[i];
			if(generate(i+1,matchsticks,target,bucket))
				return true;
			bucket[j]-=matchsticks[i];	//回溯 不装 
		} 	
		return false;
	}

full code

class Solution {
    
    
public:
	bool generate(int i,vector<int> &matchsticks,int target,int bucket[])
	{
    
    
		//出口 
		if(i>=matchsticks.size())
		{
    
    
			return bucket[0]==target&&bucket[1]==target&&
			bucket[2]==target&&bucket[3]==target;
		}
		//现在能做的事情
		for(int j=0;j<4;j++)	//分别向四个桶里装火柴 
		{
    
    
			if(bucket[j]+matchsticks[i]>target)
				continue;
			bucket[j]+=matchsticks[i];
			if(generate(i+1,matchsticks,target,bucket))
				return true;
			bucket[j]-=matchsticks[i];	//回溯 不装 
		} 	
		return false;
	}
	
    bool makesquare(vector<int>& matchsticks) {
    
    
		if(matchsticks.size()<4)
			return false;
		 int sum=0;
		 for(int i=0;i<matchsticks.size();i++)
		 	sum+=matchsticks[i];
		if(sum%4!=0)
			return false;
		sort(matchsticks.rbegin(),matchsticks.rend());
		int bucket[4]={
    
    0};
		return generate(0,matchsticks,sum/4,bucket);
    }
};

Summarize:

If you can't think of a good solution when you encounter an algorithm problem, you should first think of a violent method, then estimate the time complexity, perform various optimizations, pruning, memoization, etc. After all, in many cases, memoization search is basically equivalent to dynamic planning

Guess you like

Origin blog.csdn.net/weixin_46035615/article/details/123956719