Skip to content

Commit 8146395

Browse files
Update jeremymanning.md
1 parent 168f953 commit 8146395

File tree

1 file changed

+100
-2
lines changed

1 file changed

+100
-2
lines changed

problems/564/jeremymanning.md

+100-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,109 @@
11
# [Problem 564: Find the Closest Palindrome](https://leetcode.com/problems/find-the-closest-palindrome/description/?envType=daily-question)
22

33
## Initial thoughts (stream-of-consciousness)
4+
- One interesting aspect of the problem is that `n` is limited to at most 18 digits. So I'm guessing the algorithm will be $O(\mathrm{len}(n)^x)$, where $x$ is potentially something large.
5+
- Off the top of my head, I can see a few categories of scenarios we might encounter:
6+
- If `n` is *already* a palindrome, then we need to find a *different* palindrome.
7+
- If `len(n)` is odd, we can just add or subtract 1 (as allowed) to the middle digit and see which is closer to `n` (or if they're equally close, just subtract 1).
8+
- If `len(n)` is even, it's trickier. I guess we could add or subtract 1 to the *two* middle digits (again, as allowed)
9+
- If `n` is *not* a palindrome, then:
10+
- If `len(n)` is odd, maybe we just return `n[:len(n)//2 + 1] + n[:len(n)//2][::-1]`?
11+
- And if `len(n)` is even, we could return `n[:len(n)//2] + n[:len(n)//2][::-1]`?
12+
- The problem must not be this simple. Let's make something up...suppose `n = "293847"`. Since `n` is not a palindrome, and `len(n)` is even, is `293392` the closest palindrome? The difference is 455. What about 294492? The difference is 645, which is larger. But maybe there's a scenario where increasing or decreasing the middle digits might be helpful? I don't think it could hurt to check. It'd still be a very simple/fast solution.
13+
- What if `n = 9283743`? Then, using the above procedure, we'd return 9283829 (diff = 86). What about 9284829? (diff = 1086, which is larger). Or 9282829? (diff = 914, which is also larger than 86).
14+
- One scenario we'll need to cover is if `len(n) == 1`. If `n == '0'` then we just return `'1'`. Otherwise we should return `str(int(n) - 1)`.
15+
- Hmm. Well...I suppose we can just try this and see what happens? We'll need to test with a bunch of examples.
416

517
## Refining the problem, round 2 thoughts
18+
- First we'll need to check if `n` is a palindrome. We could use:
19+
```python
20+
def is_palindrome(n):
21+
return n[:len(n) // 2] == n[-(len(n) // 2):][::-1]
22+
```
23+
- Actually, this was easier than I thought it'd be-- we don't need to differentiate from even vs. odd-length `n`s, since the middle digit doesn't matter if `len(n)` is odd (it doesn't affect the "palindrome" status of `n`).
24+
- We can also write a convenience function to check distances between string representations of different numbers:
25+
```python
26+
def dist(a, b):
27+
return abs(int(a) - int(b))
28+
```
29+
- And also some code for incrementing or decrementing the middle digit(s):
30+
```python
31+
def wiggle_middle_digits(n):
32+
x1 = n.copy()
33+
x2 = n.copy()
34+
35+
x1_middle = str(int(n[len(n) // 2]) - 1)
36+
x2_middle = str(int(n[len(n) // 2]) + 1)
37+
38+
if len(n) % 2 == 0:
39+
x1[len(n) // 2] = x1_middle
40+
x1[len(n) // 2 + 1] = x1_middle
41+
x2[len(n) // 2] = x2_middle
42+
x2[len(n) // 2 + 1] = x2_middle
43+
else:
44+
x1[len(n) // 2 + 1] = x1_middle
45+
x2[len(n) // 2 + 1] = x2_middle
46+
47+
if dist(n, x1) <= dist(n, x2):
48+
return x1
49+
else:
50+
return x2
51+
```
52+
53+
- Other than that, we just need to implement the above rules. Let's see if it works!
654

755
## Attempted solution(s)
856
```python
9-
class Solution: # paste your code here!
10-
...
57+
from copy import copy
58+
59+
class Solution:
60+
def nearestPalindromic(self, n: str) -> str:
61+
def is_palindrome(n):
62+
return n[:len(n) // 2] == n[-(len(n) // 2):][::-1]
63+
64+
def dist(a, b):
65+
return abs(int(a) - int(b))
66+
67+
def wiggle_middle_digits(n):
68+
x1 = list(copy(n))
69+
x2 = list(copy(n))
70+
71+
x1_middle = str(int(n[len(n) // 2]) - 1)
72+
x2_middle = str(int(n[len(n) // 2]) + 1)
73+
74+
if len(n) % 2 == 0:
75+
x1[len(n) // 2] = x1_middle
76+
x1[len(n) // 2 + 1] = x1_middle
77+
x2[len(n) // 2] = x2_middle
78+
x2[len(n) // 2 + 1] = x2_middle
79+
else:
80+
x1[len(n) // 2 + 1] = x1_middle
81+
x2[len(n) // 2 + 1] = x2_middle
82+
83+
x1 = ''.join(x1)
84+
x2 = ''.join(x2)
85+
86+
if dist(n, x1) <= dist(n, x2):
87+
return x1
88+
else:
89+
return x2
90+
91+
if len(n) == 1:
92+
if n == "0":
93+
return "1"
94+
else:
95+
return str(int(n) - 1)
96+
97+
if is_palindrome(n):
98+
return wiggle_middle_digits(n)
99+
elif len(n) % 2 == 0:
100+
return n[:len(n)//2] + n[:len(n)//2][::-1]
101+
else:
102+
return n[:len(n)//2 + 1] + n[:len(n)//2][::-1]
11103
```
104+
- Both given test cases pass
105+
- Let's try a bunch of other examples:
106+
- `n = "32459827345987"`: pass
107+
- `n = "4387348756345786"`: pass
108+
- `n = "438734878437834": fail! (note: I also had to fix up the "wiggle" code syntax).
109+
- There seems to be an issue with the `wiggle_middle_digits` code-- it doesn't seem to be working as expected. However, I'm out of time for tonight, so I'll have to come back to this!

0 commit comments

Comments
 (0)