From b18a92c9fd006bc8b1086a4050baf9ac88a5c112 Mon Sep 17 00:00:00 2001 From: Albert Hu Date: Sun, 30 Apr 2017 23:54:18 -0700 Subject: [PATCH 1/2] Day 21: helpingStephan codefights --- day21/README.md | 50 +++++++++++++++++++++++++++++++++++++++++ day21/helpingStephan.py | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 day21/README.md create mode 100644 day21/helpingStephan.py diff --git a/day21/README.md b/day21/README.md new file mode 100644 index 0000000..c32b785 --- /dev/null +++ b/day21/README.md @@ -0,0 +1,50 @@ +Question of the day: https://codefights.com/challenge/hT9JyzWh77Y6NR2Qd + +Stephan is a little boy who loves math. It came as a revelation to him that +one can define the greatest common divisor for rational numbers, not just +for integers. He's decided to dig into the subject and analyze the properties +of this new-to-him GCD. + +Stephan needs lots of GCDs to gather all possible information about them. But +Stephan is still a little boy and he can't calculate the GCD of two numbers as +quickly as he'd like. So he asks for your help: Given float numbers x and y, +calculate their greatest common divisor. + +It is guaranteed that both x and y will have at most 5 digits after the decimal +point. + +Example: + +For `x = 2.4` and `y = 4.8`, the output should be +`helpingStephan(x, y) = 2.4`. + +## Ideas + +How do I even find GCD without decimals? uhhhhh.... + +Prime factorization? That seems complicated but doable for small numbers. +I can get the prime factorization of each number by repeatedly dividing +primes in increasing magnitude up to the value of the number, and keeping +the number of times each prime divides into the number in a hash. Then get +the primes that each number has in common and get the `min` between them. + +Let me just google this.. + +Aha! [Euclid's Algorithm](https://en.wikipedia.org/wiki/Greatest_common_divisor#Using_Euclid.27s_algorithm) +I totally learned this in Algorithms class in college but forgot it existed. + +Not sure what the runtime is for this algorithm, but this stack overflow post +kinda explains it: http://stackoverflow.com/questions/3980416/time-complexity-of-euclids-algorithm + +So I could just change the floats that I'm given into ints by multiplying by +a factor of 10, apply Euclid's Algorithm in `O(n)` runtime where `n` is +proportional to the value of the input numbers, and then divide by the earlier +factor of 10 I used to multiply. + +## Code + +[Python](helpingStephan.py) + +## Follow up + +Floats.. https://docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues diff --git a/day21/helpingStephan.py b/day21/helpingStephan.py new file mode 100644 index 0000000..f9d5ff3 --- /dev/null +++ b/day21/helpingStephan.py @@ -0,0 +1,40 @@ +def helpingStephan(x, y): + xSplit = str(x).split(".") + ySplit = str(y).split(".") + + XdigitsAfterDecimal = "0" + if len(xSplit) > 1: + XdigitsAfterDecimal = xSplit[1] + + YdigitsAfterDecimal = "0" + if len(ySplit) > 1: + YdigitsAfterDecimal = ySplit[1] + + + digitsAfterDecimal = max(len(XdigitsAfterDecimal), len(YdigitsAfterDecimal)) + + x *= 10**digitsAfterDecimal + y *= 10**digitsAfterDecimal + + a = max(x, y) + b = min(x, y) + + r = -1 + while r != 0: + r = round(a % b, 6) * 1.0 + a = b + b = r + + return a / 10**digitsAfterDecimal + +def main(): + assert helpingStephan(2.4, 4.8) == 2.4 + assert helpingStephan(36.21, 4.19) == 0.01 + assert helpingStephan(4, 6) == 2 + assert helpingStephan(2.43, 4.899) == 0.003 + assert helpingStephan(47.804, 11.8683) == 0.0001 + assert helpingStephan(17.27568, 49.90752) == 1.91952 + assert helpingStephan(22.14728, 11.07364) == 11.07364 + +if __name__ == "__main__": + main() From 88ea6b1ad0f4c19b21a1401332284eb8263c1494 Mon Sep 17 00:00:00 2001 From: Albert Hu Date: Wed, 3 May 2017 21:26:54 -0700 Subject: [PATCH 2/2] Day 21: Assume 5 digit max after decimal point --- day21/helpingStephan.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/day21/helpingStephan.py b/day21/helpingStephan.py index f9d5ff3..e4d33ac 100644 --- a/day21/helpingStephan.py +++ b/day21/helpingStephan.py @@ -1,17 +1,5 @@ def helpingStephan(x, y): - xSplit = str(x).split(".") - ySplit = str(y).split(".") - - XdigitsAfterDecimal = "0" - if len(xSplit) > 1: - XdigitsAfterDecimal = xSplit[1] - - YdigitsAfterDecimal = "0" - if len(ySplit) > 1: - YdigitsAfterDecimal = ySplit[1] - - - digitsAfterDecimal = max(len(XdigitsAfterDecimal), len(YdigitsAfterDecimal)) + digitsAfterDecimal = 5 x *= 10**digitsAfterDecimal y *= 10**digitsAfterDecimal @@ -21,13 +9,14 @@ def helpingStephan(x, y): r = -1 while r != 0: - r = round(a % b, 6) * 1.0 + r = round(a % b, 6) a = b b = r return a / 10**digitsAfterDecimal def main(): + assert helpingStephan(1, 1) == 1 assert helpingStephan(2.4, 4.8) == 2.4 assert helpingStephan(36.21, 4.19) == 0.01 assert helpingStephan(4, 6) == 2