我试着为这个问题编写一个代码:
(来源:https://www.codewars.com/kata/insane-coloured-triangles/train/c)
一个彩色三角形由一行颜色组成,每一行颜色为红、绿色或蓝。通过考虑前一行中的两种接触颜色,生成连续的行,每行包含的颜色比上一行少一种。如果这些颜色相同,则在新行中使用相同的颜色。如果它们不同,则在新行中使用缺失的颜色。这一直持续到最后一行。只有一种颜色。
例如,不同的可能性是:
Colour here: G G B G R G B R
Becomes colour here: G R B G
With a bigger example:
R R G B R G B B
R B R G B R B
G G B R G G
G R G B G
B B R R
B G R
R B
G
你将得到三角形的第一行作为字符串,你的任务是返回最后一行作为字符串出现的颜色。在上面的例子中,你将得到'RRGBRGBB'
,你应该返回'G'
。
制约因素:
输入字符串将只包含大写字母B', 'G' or 'R'
。
测试用例的确切数量如下所示:
100 tests of 100 <= length(row) <= 1000
100 tests of 1000 <= length(row) <= 10000
100 tests of 10000 <= length(row) <= 100000
示例:
triangle('B') == 'B'
triangle('GB') == 'R'
triangle('RRR') == 'R'
triangle('RGBG') == 'B'
triangle('RBRGBRB') == 'G'
triangle('RBRGBRBGGRRRBGBBBGG') == 'G'
因此,我做了这个代码,它适用于所有的样本口味,但当它涉及到length of row > 25
时,由于我的阶乘函数而失败,并且在某些情况下长度高达100,000
,所以任何解决这个问题的建议至少可以解决这个问题的任何数学公式或一个小提示。
顺便说一句,我在这个网站上找到了一个数学方法来解决这个问题后,我做了这个代码:
https://math.stackexchange.com/questions/2257158/three-color-triangle-challenge
long long factorial(long long num)
{
long long fact = num;
if (fact == 0)
fact = 1;
while (num > 1)
{
num--;
fact *= num;
}
return (fact);
}
long long combination(long long n, long long k, long long fact_n)
{
long long fact_k = factorial(k);
long long comb = ( fact_n / (fact_k * factorial(n - k)) );
return (comb);
}
char triangle(const char *row)
{
long long len = strlen(row);
long long n = len - 1;
long long k = 0;
int sign = pow(-1,n);
long long sum = 0;
char *result = "RGB";
int a;
long long fact_n = factorial(n);
while (k < len) //This while calculate Segma (∑).
{
if (row[k] == 'R')
a = 0;
else if (row[k] == 'G')
a = 1;
else if (row[k] == 'B')
a = 2;
if (a != 0)
sum = sum + (combination(n,k,fact_n) * a);
k++;
}
sum = sign * (sum % 3);
if (sum == -1 || sum == -2)
sum += 3;
return (result[sum]);
}
4条答案
按热度按时间t0ybt7op1#
我假设您提供的链接中的公式是正确的:
为了避免整数溢出,我们需要应用这些模算术规则:
将它们应用于公式:
但是我们怎么计算呢
...而不直接计算系数本身(这可能导致溢出)?
由于3是一个质数,这可以通过**Lucas's theorem**来实现:
...其中
n_i, m_i
是n, m
在 base-3 中的第i
位。使用整数除法可以很容易地转换为基数3:
注意,由于
n_i, m_i
总是在[0, 2]
的范围内(因为它们是以3为基数的数字),所以C(n_i, m_i)
非常容易计算:现在是定理本身:
字符转换:
最后,三角形算法:
上面的代码通过了所有的测试。请注意,它是为了清晰而不是性能而编写的。
那么,为什么这段代码能够在分配的时间内通过所有测试,而简单的基于表的方法却不能呢?因为它的时间复杂度:
O(n^2)
**(参见Triangle Numbers)。O(log n)
,因为它循环通过n
的每个数字(无论基数如何)。总体复杂度是**O(n log n)
**,这仍然代表着显着的改进。jexiocij2#
x7yiwoj43#
j5fpnvbx4#
递归在这里没有什么用处,因为你永远不需要返回到以前的状态。迭代是一个更好的解决方案,而且可以相当简单地完成。
对初始字符串的更改也可以就地进行,因为一旦使用和更改了初始值,就不需要返回到原始值。
方法如下。只要字符串大于一个字符,就处理原始字符串中的每组两个字符(重叠)。
对于该对,根据规则更改第一个字符。当所有对都完成时,从字符串中删除最后一个字符,从而使字符串少一个字符。
下面是一些示例代码,其中包含不必要但有用的检查和输出函数:
当使用参数
RRGBRGBB
运行时,该代码的输出如预期的那样:它也适用于字符串的极限(100,000个字符)但请记住它是O(n2)解决方案,因此会随着大小的增大而变慢。对随机100,000个字符的字符串的测试运行在不到15秒的时间内完成,因此,如果需要比这更快,则此解决方案将不适合。为了完整性,下面是我系统上各种输入大小的运行时表(禁用调试输出):
它跨越了一秒的阈值,大约在20,000到30,000个字符之间。