Skip to content

Commit 21d68f9

Browse files
lufftwclaude
andcommitted
feat(solutions): Add 0050 Pow(x, n)
Two approaches: Iterative binary exponentiation (O(log n) time, O(1) space) decomposes n into binary bits; Recursive (O(log n) time, O(log n) space) uses divide and conquer. Both handle negative exponents. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 9c667cd commit 21d68f9

9 files changed

Lines changed: 261 additions & 0 deletions

File tree

generators/0050_powx_n.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# generators/0050_powx_n.py
2+
"""
3+
Test Case Generator for Problem 0050 - Pow(x, n)
4+
5+
LeetCode Constraints:
6+
- -100.0 < x < 100.0
7+
- -2^31 <= n <= 2^31 - 1
8+
- -10^4 <= x^n <= 10^4
9+
"""
10+
import json
11+
import random
12+
from typing import Iterator, Optional
13+
14+
15+
def generate(count: int = 10, seed: Optional[int] = None) -> Iterator[str]:
16+
"""Generate random test cases for Pow(x, n)."""
17+
if seed is not None:
18+
random.seed(seed)
19+
20+
# Edge cases
21+
edge_cases = [
22+
(2.0, 10), # Simple power
23+
(2.1, 3), # Floating point base
24+
(2.0, -2), # Negative exponent
25+
(1.0, 1000000), # Large exponent with base 1
26+
(0.0, 5), # Zero base
27+
]
28+
29+
for x, n in edge_cases:
30+
yield f"{x}\n{n}"
31+
count -= 1
32+
if count <= 0:
33+
return
34+
35+
for _ in range(count):
36+
yield _generate_random_case()
37+
38+
39+
def _generate_random_case() -> str:
40+
"""Generate a random x and n with valid result range."""
41+
# Keep x and n small to avoid overflow
42+
x = round(random.uniform(-10, 10), 5)
43+
if abs(x) < 0.1:
44+
x = random.choice([-1.0, 1.0, 2.0])
45+
46+
# Limit n to keep result in range
47+
max_n = 20 if abs(x) > 1 else 100
48+
n = random.randint(-max_n, max_n)
49+
50+
# Avoid 0^negative
51+
if x == 0 and n < 0:
52+
n = abs(n)
53+
54+
return f"{x}\n{n}"
55+
56+
57+
def generate_for_complexity(n: int) -> str:
58+
"""
59+
Generate test case with exponent n for complexity estimation.
60+
"""
61+
n = max(-1000, min(n, 1000))
62+
x = 1.0001 if n > 0 else 0.9999
63+
return f"{x}\n{n}"
64+
65+
66+
if __name__ == "__main__":
67+
for i, test in enumerate(generate(5, seed=42), 1):
68+
lines = test.split("\n")
69+
print(f"Test {i}: {lines[0]}^{lines[1]}")

meta/problems/0050_powx_n.toml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Problem: Pow(x, n)
2+
# https://leetcode.com/problems/powx-n/
3+
4+
id = "0050"
5+
slug = "0050_powx_n"
6+
title = "Pow(x, n)"
7+
leetcode_id = 50
8+
url = "https://leetcode.com/problems/powx-n/"
9+
10+
difficulty = "medium"
11+
topics = ["math", "recursion"]
12+
companies = ["facebook", "amazon", "google"]
13+
roadmaps = ["neetcode_150"]
14+
15+
api_kernels = ["BinaryExponentiation"]
16+
patterns = ["exponentiation_by_squaring", "divide_and_conquer"]
17+
families = ["math"]
18+
data_structures = []
19+
algorithms = ["binary_exponentiation"]
20+
related_problems = ["0069", "0372"]
21+
22+
[files]
23+
solution = "solutions/0050_powx_n.py"
24+
generator = "generators/0050_powx_n.py"
25+
tests_dir = "tests/"
26+
27+
[[solutions]]
28+
key = "default"
29+
class = "SolutionIterative"
30+
method = "myPow"
31+
complexity = "O(log n) time, O(1) space"
32+
notes = "Iterative binary exponentiation"
33+
34+
[[solutions]]
35+
key = "recursive"
36+
class = "SolutionRecursive"
37+
method = "myPow"
38+
complexity = "O(log n) time, O(log n) space"
39+
notes = "Recursive divide and conquer"

solutions/0050_powx_n.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# solutions/0050_powx_n.py
2+
"""
3+
Problem: Pow(x, n)
4+
https://leetcode.com/problems/powx-n/
5+
6+
Implement pow(x, n), which calculates x raised to the power n.
7+
8+
Constraints:
9+
- -100.0 < x < 100.0
10+
- -2^31 <= n <= 2^31 - 1
11+
- n is an integer
12+
- Either x is not zero or n > 0
13+
- -10^4 <= x^n <= 10^4
14+
"""
15+
from _runner import get_solver
16+
17+
SOLUTIONS = {
18+
"default": {
19+
"class": "SolutionIterative",
20+
"method": "myPow",
21+
"complexity": "O(log n) time, O(1) space",
22+
"description": "Iterative binary exponentiation",
23+
},
24+
"recursive": {
25+
"class": "SolutionRecursive",
26+
"method": "myPow",
27+
"complexity": "O(log n) time, O(log n) space",
28+
"description": "Recursive binary exponentiation",
29+
},
30+
}
31+
32+
33+
class SolutionIterative:
34+
"""
35+
Iterative binary exponentiation (exponentiation by squaring).
36+
37+
Key insight: x^n can be computed in O(log n) multiplications by
38+
decomposing n into binary. For example, x^13 = x^8 * x^4 * x^1
39+
since 13 = 1101 in binary.
40+
41+
At each step, we check if current bit is set (n & 1). If so,
42+
multiply result by current power of x. Then square x and shift n.
43+
Handles negative exponents by inverting x and negating n.
44+
"""
45+
46+
def myPow(self, x: float, n: int) -> float:
47+
# Handle negative exponent: x^(-n) = (1/x)^n
48+
if n < 0:
49+
x = 1 / x
50+
n = -n
51+
52+
result = 1.0
53+
54+
while n > 0:
55+
# If current bit is set, multiply result by current power
56+
if n & 1:
57+
result *= x
58+
59+
# Square x for next bit position
60+
x *= x
61+
# Move to next bit
62+
n >>= 1
63+
64+
return result
65+
66+
67+
class SolutionRecursive:
68+
"""
69+
Recursive binary exponentiation with divide and conquer.
70+
71+
The recurrence relation is:
72+
- x^n = (x^(n/2))^2 if n is even
73+
- x^n = x * (x^(n/2))^2 if n is odd
74+
- x^0 = 1 (base case)
75+
76+
This naturally halves the problem each step, giving O(log n) depth.
77+
Uses O(log n) stack space for recursion.
78+
"""
79+
80+
def myPow(self, x: float, n: int) -> float:
81+
# Handle negative exponent
82+
if n < 0:
83+
x = 1 / x
84+
n = -n
85+
86+
return self._pow(x, n)
87+
88+
def _pow(self, x: float, n: int) -> float:
89+
# Base case
90+
if n == 0:
91+
return 1.0
92+
93+
# Recursive case: compute x^(n/2)
94+
half = self._pow(x, n // 2)
95+
96+
# Square the result
97+
if n % 2 == 0:
98+
return half * half
99+
else:
100+
return half * half * x
101+
102+
103+
def judge(actual, expected, input_data: str) -> bool:
104+
"""
105+
Validate power computation with tolerance for floating point.
106+
"""
107+
import json
108+
109+
lines = input_data.strip().split("\n")
110+
x = json.loads(lines[0])
111+
n = json.loads(lines[1])
112+
113+
# Compute expected using Python's pow
114+
expected_result = pow(x, n)
115+
116+
# Allow small relative error for floating point
117+
if expected_result == 0:
118+
return abs(actual) < 1e-9
119+
return abs(actual - expected_result) / abs(expected_result) < 1e-5
120+
121+
122+
JUDGE_FUNC = judge
123+
124+
125+
def solve():
126+
import sys
127+
import json
128+
129+
lines = sys.stdin.read().strip().split("\n")
130+
131+
# Parse input: x and n
132+
x = json.loads(lines[0])
133+
n = json.loads(lines[1])
134+
135+
# Get solver and compute power
136+
solver = get_solver(SOLUTIONS)
137+
result = solver.myPow(x, n)
138+
139+
# Output with reasonable precision
140+
print(json.dumps(result, separators=(",", ":")))
141+
142+
143+
if __name__ == "__main__":
144+
solve()

tests/0050_powx_n_1.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2.00000
2+
10

tests/0050_powx_n_1.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1024.00000

tests/0050_powx_n_2.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2.10000
2+
3

tests/0050_powx_n_2.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
9.26100

tests/0050_powx_n_3.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2.00000
2+
-2

tests/0050_powx_n_3.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.25000

0 commit comments

Comments
 (0)