【华为练习题】求麻将清一色和牌问题

【华为练习题】求麻将清一色和牌问题

题目

题目描述:
清一色是麻将番种之一,指由一种花色的序数牌组成的和牌.
数字1-9,每个数字最多有4张牌
我们不考虑具体花色,我们只看数字组合。
刻子:三张一样的牌;如: 111, 222, 333, …, 999
顺子:三张连续的牌;如: 123, 234, 345, …, 789
对子:两张相同的牌;如: 11, 22, 33, …, 99
需要实现一个程序,判断给定牌,是否可以和牌(胡牌)。
和牌要求:

  • 麻将牌张数只能是 2, 5, 8, 11, 14
  • 给定牌可以组合成,除1个对子以外其他都是刻子或顺子
    举例: - “11” -> “11”, 1对子,可以和牌
  • “11122233” -> “111”+“222”+“33”, 2刻子,1对子,可以
  • “11223344567” -> “11”+“234”+“234”+“567”, 1对子,3顺子,可以
    -> “123”+“123”+“44”+“567”, 另一种组合,也可以
    输入描述:
    合法C字符串,只包含’1’-‘9’,且已经按从小到大顺序排好;字符串长度不超过15。同一个数字最多出现4次,与实际相符。
    输出描述:
    C字符串,“yes"或者"no”
    示例1
    输入
    2244
    输出
    24 //此处是试题原本模样,应该输出no

分析

可用递归的方式求解,在字符串中搜索刻子和顺子,找到之后再对去掉刻子或顺子之后的字符串进行递归搜索,直到字符串长度小于3为止,若最终剩余字符串长度为2且两个字符相同时则胡牌,否则不能胡牌。

解答

#include 
#include 
using namespace std;

// 判断麻将是否和牌
bool canSuccess(const string &s) {
	// 字符串长度不符合
	if (s.length() < 2 || s.length() >= 15) return false;
	// 剩下的2张牌为对子则和牌否则不能和牌
	if (s.length() == 2) return s[0] == s[1];
	bool flag = false;
	auto begin= s.begin(), end = s.end();
	while (end - begin > 2)
	{
		// 判断是否有刻子
		if (*begin == *(begin + 1) && *begin == *(begin + 2))
		{
			// 去掉刻子后递归处理
			string tmp1(s.begin(), begin);
			string tmp2(begin + 3, end);
			flag |= canSuccess(tmp1 + tmp2);
		}
		// 判断是否有顺子
		else if (*begin + 1 == *(begin + 1)) {
			// 顺子中间的牌可能有多张相同的,遍历找到第一个不同的
			int midSameCount = 0;
			char mid = *(begin + 1);
			auto iter = begin + 1;
			while (*iter == mid)
			{
				midSameCount++;
				// 如果递归到字符串末则标记后退出循环
				if (++iter == end)
				{
					midSameCount = -1;
					break;
				}
			}
			// 处理有顺子的情况
			if (midSameCount > 0 && mid + 1 == *iter) {
				// 去掉顺子后递归处理
				string tmp1(s.begin(), begin);
				string tmp2;
				tmp2.insert(0, midSameCount - 1, mid);
				string tmp3(iter + 1, end);
				flag |= canSuccess(tmp1 + tmp2 + tmp3);
			}

		}
		++begin;
	}
	return flag;
}

int main()
{
	string input;
	getline(cin, input);
	bool flag = canSuccess(input);
	cout << (flag ? "yes" : "no") << endl;
}

你可能感兴趣的:(C++,C++面试总结)