Levenshtein Neighbours

Most square numbers have at least 1 different square number with which their Levenshtein distance is exactly 1. For a given square $$\x\$$, each square that meets this condition is called a Levenshtein neighbour of $$\x\$$. For example, $$\36\$$ is a Levenshtein neighbour of $$\16\$$, as only 1 edit ($$\1 \to 3\$$) is required. However, $$\64\$$ is not a Levenshtein neighbour of $$\16\$$, as it requires a minimum of 2 edits. Numbers that have leading 0s ($$\2025 \to 025\$$) are not Levenshtein neighbours.

Your task is to take a square number as input and to output, in any reasonable format, the complete list of it's Levenshtein neighbours. You may include repeat neighbours in the list, if you wish, but you may not include the original input, as it isn't a Levenshtein neighbour of itself.

Any reasonable format should include some sort of separator between the outputs, such as , or a newline, and can output characters with the corresponding Unicode value (i.e. brainfuck) rather than the numbers themselves. The order of the output doesn't matter.

This input will always be a square number, greater than $$\0\$$. Your program should have no theoretical limit, but if it fails for large numbers for practical reasons (e.g. beyond 32-bit numbers), that's completely fine.

If the input does not have any Levenshtein neighbours, the output must clearly reflect this, such as outputting nothing, an empty array/string, a negative integer, $$\0\$$, etc.

This is , so the shortest code in bytes wins.

Test cases

These are the results for the squares of $$\1\$$ through to $$\20\$$:

1: 4, 9, 16, 81
4: 1, 9, 49, 64
9: 1, 4, 49
16: 1, 36, 169, 196
25: 225, 256, 625
36: 16, 361
49: 4, 9
64: 4
81: 1, 841
100: 400, 900, 1600, 8100
121: 1521
144: 1444
169: 16, 1369
196: 16, 1296, 1936
225: 25, 625, 1225, 2025, 4225, 7225
256: 25
289: 2809
324: 3249
361: 36, 961
400: 100, 900, 4900, 6400

In addition, 1024 does not have any neighbours, so is a good test case.

• More interesting would be what the neighbours of 2025 are. – Neil Aug 17 at 23:21
• Unless I'm missing something, 32 * 32 = 1024 has no square Levenshtein neighbours. – xnor Aug 17 at 23:29
• @xnor Yes, I believe you are right, 1024 does not have any Levenshtein neighbours, I'll edit that example in – caird coinheringaahing Aug 17 at 23:38
• For all statements of the form "For all...", if a counterexample can be found, then this is a rigorous disproof of the statement. (But if I'm wrong, I'll accept a counterexample as a rigorous disproof.) – Neil Aug 17 at 23:40
• May we include the original number in the output? For example 49 -> 4, 9, 49. – Robin Ryder Aug 18 at 9:02

05AB1E,  11 10  6 bytes

-4 thanks to Grimy !! (square first rather than looking for squares saves 3; use 10^n saves 1)

°Lnʒ.L

Takes an integer, outputs a, possibly empty, list

Try it online! - This is crazy-slow due to the °, so no point trying it even for 9.
Or Try a slightly faster version - This one adds eight instead with 8+ then uses the same approach.

How?

°Lnʒ.L - f(integer)    stack = n
°      - push 10^n             10^n
L     - range                 [1,2,3,...,10^n]
n    - square                [1,4,9,...,10^2n]
ʒ   - filter keep if == 1:
.L -   Levenshtein distance
• The 9s« in your 11-byter could have been . Nice to-the-point answer, though! +1 from me. – Kevin Cruijssen Aug 19 at 7:20
• Slower 7: т+Lnʒ.L. Ridiculously slow 6: °Lnʒ.L. Infinitely slow 5: ∞nʒ.L. – Grimy Aug 19 at 13:36
• @Grimy Thanks - why on earth did I not think to square first :/. Is that infinite one acceptable for a "show all" question? (I see we can submit generators as function submissions, but if there is no coded stop point then we cannot know when it's given us the final value). – Jonathan Allan Aug 19 at 14:00
• I don't think ∞nʒ.L is acceptable as an answer because submissions have to terminate. Unrelated: your TIO link for the 7-byte version uses , which is ~100x slower than T+ for large numbers. My comment used т+ (add 100) to be safe, but it turns out 8+ is enough in all cases. – Grimy Aug 19 at 14:42
• @Grimy oops, thanks. I figured 100 was overkill since 1 only needs to check the first 9 squares. – Jonathan Allan Aug 19 at 16:34

Retina 0.8.2, 142 138 bytes

.?
$'¶$#$&$'¶$#$'¶$$&
#
0$%'¶$%1$%'¶$%2$%'¶$%3$%'¶$%4$%'¶$%5$%'¶$%6$%'¶$%7$%'¶$%8$%'¶$%9
A^0
Dr
\d+
$* -2G(\b1|11\1)+\b %1 Try it online! Explanation: .?$'¶$#$&$'¶$#$'¶$$& For each digit, try a) removing it b) preceding it with a different digit c) changing it to a different digit. For now, the different digit is marked with a #. # 0$%'¶$%1$%'¶$%2$%'¶$%3$%'¶$%4$%'¶$%5$%'¶$%6$%'¶$%7$%'¶$%8$%'¶$%9 For each potential different digit, substitute each possible digit. A^0 Remove numbers that now begin with zero. Dr Remove all duplicated numbers. (This just leaves the lines blank.) \d+$*

Convert to unary.

-2G(\b1|11\1)+\b

Keep all square numbers except the last (which is always the input number).

%1

Convert the remaining numbers back to decimal.

R, 42 41 bytes

-1 byte with the bound $$\(9n)^2\$$.

Try it online!

All Levenshtein neighbours of $$\n\$$ are smaller than $$\91n\$$ (That bound is attained, for example, by $$\1\to 91\$$ or $$\100\to9100\$$). Here, I am using instead the bound $$\(9n)^2=81n^2\$$. For $$\n>1\$$, $$\81n^2>91n\$$ so we are fine. For $$\n=1\$$, this bound misses one Levenshtein neighbour: $$\1\to91\$$; since $$\91\$$ is not a square, we are fine.

Lists all square numbers between $$\1\$$ and $$\(9n)^2\$$, and keeps those with Levenshtein distance equal to 1.

Python 2, 173167149148147144139 138 bytes

lambda n,I=int:{(I(I(v)**.5)**2==I(v))*I(v)for v in[n[:i]+j-1[:j]+n[i+k:]or 0for j in range(11)for i in range(n)for k in 0,1]}-{0,n}

Try it online!

19+3+5+1=28! bytes thx to Jonathan Allan.

• Save 48. [p for p in...]is redundant. We can return a set (or duplicates). '0'<v[:1] can be '1'<=v. It's much slower but range(len(a)+1) can be range(n). Use a variable for i and i+1 slices to avoid the sum. Use a lambda. EDIT save 48 from your previous. – Jonathan Allan Aug 18 at 2:04
• @Jonathan Allan: I'd already made some of the same changes; but definitely appreciate the 18 bytes! – Chas Brown Aug 18 at 2:25
• Another one – Jonathan Allan Aug 18 at 2:30
• @Jonathan Allan: Nice! It's now barely readable :). – Chas Brown Aug 18 at 2:34
• @Jonathan Allan: Lol, I'm just gonna stop updating - I can't keep up! :) – Chas Brown Aug 18 at 2:46

Oracle SQL, 93 bytes

select level*level from t where utl_match.edit_distance(x,level*level)=1connect by level<10*x

Test in SQL*PLus.

SQL> set heading off
SQL> with t(x) as (select 225 from dual)
2  select level*level from t where utl_match.edit_distance(x,level*level)=1connect by level<10*x
3  /

25
625
1225
2025
4225
7225

6 rows selected.

PHP, 62 bytes

for(;$argn*92>$n=++$i**2;levenshtein($argn,$n)==1&&print$n._);

Try it online!

This script prints Levenshtein neighbors of input separated by _ with a trailing separator, and if no neighbors are found, prints nothing.

Happily PHP has a built-in for Levenshtein distance! This script loops over all square numbers from 1 to input * 91, since all valid Levenshtein neighbors (distance of 1) are in that range. Then prints every number in that range which has a Levenshtein distance of 1 with the input.

JavaScript (V8),  129 125  123 bytes

Takes input as a string. Prints the Levenshtein neighbours to STDOUT.

s=>{for(t=9+s;t;t--)(t+='')**.5%1||(g=m=>m*n?1+g(m,--n)*(g(--m)-(s[m]==t[n++]))*g(m):m+n)(s.length,n=t.length)-1||print(t)}

Try it online!

Commented

s => {                        // s = input
for(                        // loop:
t = 9 + s;                //   start with t = '9' + s
t;                        //   repeat while t > 0
t--                       //   decrement t after each iteration
)                           //
(t += '')                 //   coerce t to a string
** .5 % 1 ||              //   abort if t is not a square
( g =                     //   g is a recursive function to test whether the
//   Levenshtein distance between s and t is exactly 1
m =>                    //   m = pointer into s (explicit parameter)
//   n = pointer into t (defined in the global scope)
m * n ?               //     if both m and n are greater than 0:
1 +                 //       add 1 to the final result and add the product of:
g(m, --n) * (       //         - a recursive call with m and n - 1
g(--m) -          //         - a recursive call with m - 1 and n - 1
(s[m] == t[n++])  //           minus 1 if s[m - 1] = t[n - 1]
) *                 //
g(m)                //         - a recursive call with m - 1 and n
:                     //       else:
m + n               //         stop recursion and return m + n
)(s.length, n = t.length) //   initial call to g with m = s.length, n = t.length
- 1 ||                    //   abort if the final result is not 1
print(t)                  //   otherwise, print t
}                             //
• I knew SpiderMonkey had print() but I didn't realise Node had it as well... – Neil Aug 18 at 8:54
• @Neil Actually, it doesn't exist in Node. I think this version is just a shell build of V8 -- which is much closer to the browser version. – Arnauld Aug 18 at 9:24

Jelly, 53 38 bytes

D;Ɱ⁵ṭJœP,œṖjþ⁵Ẏṭ@ḢF${ʋʋ€$ƲẎ%⁵1ị\$ƇḌÆ²Ƈḟ

Try it online!

There’s no built-in for Levenshtein distance so generates all possible 1-distance edits and then excludes those with leading zero and keeps only perfect squares. Doesn’t filter duplicates (as permitted).

Wolfram Language (Mathematica), 62 59 bytes

f@n_:=Select[Range[9n]^2,EditDistance@@ToString/@{n,#}==1&]

Try it online!

Using the bound from the R answer.