Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Build the list of absolute differences between adjacent characters, |s[i] − s[i−1]|. Do the same for the reversed string. The string is 'funny' when those two difference lists are identical. The clean trick: you don't have to physically reverse the string — the reverse's difference at position i equals the original's difference read from the opposite end. Compare s's differences front-to-back against the same list back-to-front. O(n) time, O(1) space.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you translate the wordy definition into a concrete invariant — the adjacent absolute-difference sequence — and whether you realise reversing the string just reverses that sequence, so no extra allocation is needed.
Where candidates slip
Comparing the characters of s and its reverse instead of the differences, or forgetting the absolute value so a negative gap fails to match its positive mirror.
How to stand out
State the insight out loud: 'funny' means the difference sequence is a palindrome. Then skip building reverse(s) entirely by mirroring the index, turning O(n) extra space into O(1).
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewString sIs the gap sequence a palindrome?YesNoExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Build the Reverse and Compare Difference Lists (Baseline)
1Hint 1Explore hintHide hint
The definition mentions reverse(s) explicitly. What's the most direct way to follow it?
2Hint 2Explore hintHide hint
Physically reverse the string, then build two arrays of adjacent absolute differences — one for s, one for the reverse.
3Hint 3Explore hintHide hint
Compare the two difference arrays element by element; equal everywhere means 'Funny'.
A · Core idea
Follow the wording of the problem to the letter: form r = reverse(s), compute the adjacent absolute differences of both strings, and check the two lists are identical.
Why it is correct by construction. The problem defines 'funny' as 'the adjacent difference profiles of s and reverse(s) agree'. This approach computes exactly those two profiles and compares them, so there is no room for an off-by-one in the logic — only in the indexing.
Why absolute value is essential. |s[i] − s[i−1]| discards sign. If you kept the signed difference, the reverse would flip every sign (walking the same neighbours in the opposite direction), and almost nothing would ever be funny. Taking the absolute value is what makes the forward and mirrored gaps comparable.
Why we don't ship it. It allocates a reversed string and (often) two difference arrays — O(n) memory — to answer a yes/no question. The reverse's difference at position i is fully determined by the original string, so we can compute it on the fly and drop all the extra storage. Use this version to make the definition concrete, then fold it into the index-mirroring solution.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "acxz"reverse
r = "zxca"
have both stringsFunnyC · Code with teaching comments
Reference implementation previewpublic String funnyString(String s) { String r = new StringBuilder(s).reverse().toString(); int n = s.length(); for (int i = 1; i < n; i++) { int ds = Math.abs(s.charAt(i) - s.charAt(i - 1));Explore the full codeHide the full code
D · Why it works and complexityO(n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Writing out both difference lists makes the symmetry obvious: the reverse's list is literally s's list read backwards. That observation is the bridge to the O(1)-space version — you never needed the reversed string, only its differences, which you already have.
ComplexityO(n) time, O(n) space — Reversing is O(n), building each difference list is O(n), and comparing them is O(n) → O(n) time. Storing the reversed string and/or two difference arrays costs O(n) extra space.
E · Edge cases and pitfalls3Comparing characters of s and r instead of their adjacent differences.Explore edge casesHide edge cases
Pitfalls
- Comparing characters of s and r instead of their adjacent differences.
- Dropping the absolute value, so signed gaps never match across the reverse.
- Allocating the reversed string when an index mirror would do.
Approach 2 of 2 · Optimal
Mirror the Index — No Reverse Allocated (Optimal)
1Hint 1Explore hintHide hint
You built reverse(s) only to read its adjacent differences. Can you express the reverse's difference at position i purely in terms of s?
2Hint 2Explore hintHide hint
In the reverse, position i holds s[n-1-i]. So |r[i] - r[i-1]| = |s[n-1-i] - s[n-i]| = |s[n-i] - s[n-i-1]| in the original.
3Hint 3Explore hintHide hint
Loop i from 1 to n-1, compare |s[i] - s[i-1]| against |s[n-i] - s[n-i-1]|. No reversed string, no difference arrays — just two subtractions per step.
A · Core idea
Walk one index i from 1 to n−1. At each step compare the forward gap |s[i] − s[i−1]| with the mirrored gap |s[n−i] − s[n−i−1]|. If they ever disagree, return 'Not Funny'; survive the whole range and return 'Funny'.
Where the mirror index comes from. In the reversed string r, character at position i is the original character at position n−1−i. So the reverse's adjacent gap |r[i] − r[i−1]| equals |s[n−1−i] − s[n−1−(i−1)]| = |s[n−1−i] − s[n−i]|. Since absolute value ignores order, that's |s[n−i] − s[n−i−1]|. The reverse's gap at step i is therefore a plain expression in the original string — no r required.
Why this is the same test as the baseline. The baseline compared two lists; this compares the same two values pairwise, just sourced directly from s. As i runs forward, the mirror index n−i runs backward, so we're checking s's gap sequence against itself reversed — exactly the palindrome-of-differences condition.
Why absolute value still matters. Reading the neighbours from the opposite end swaps which one is subtracted first, flipping the sign. The absolute value erases that flip so the forward and mirrored gaps are directly comparable. Drop it and the mirror almost never matches.
Why O(1) space. The only state is the loop counter and two freshly computed integer gaps per iteration. Nothing scales with n, so memory is constant — the entire reason to prefer this over the baseline.
Why early exit is safe. A single position where the forward and mirrored gaps differ is a witness that the difference sequence is not a palindrome, which is enough to conclude 'Not Funny' without scanning the rest.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "bcxz"Array state
i=1
fwd |c-a|=2 vs mirror |z-x|=2 → match
Not FunnyC · Code with teaching comments
D · Why it works and complexityO(n) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Whenever you only need a transformed string's derived values (here, adjacent gaps) rather than the string itself, look for a closed-form index map back into the original. Reverse maps position i to n−1−i; substituting that turns an O(n)-space copy into O(1)-space arithmetic.
ComplexityO(n) time, O(1) space — A single pass with i from 1 to n−1 does O(1) work per step → O(n) time. You hold only a couple of integers, so O(1) extra space — no reversed string, no arrays.
E · Edge cases and pitfalls6s = "a" — n = 1, loop from 1 never runs → 'Funny' (no adjacent pairs to violate).Explore edge casesHide edge cases
Edge cases handled
s = "a"n = 1, loop from 1 never runs → 'Funny' (no adjacent pairs to violate).s = "aa"One gap |a-a|=0 vs mirror |a-a|=0 → 'Funny'.s = "ab"fwd |b-a|=1, mirror also |b-a|=1 (mirror reads s[1],s[0]) → 'Funny'; any 2-char string is funny.
Pitfalls
- Off-by-one on the mirror: it's s[n-i] and s[n-i-1], not s[n-1-i] alone.
- Forgetting abs(), so the sign flip from reading right-to-left breaks the match.
- Subtracting characters without code-point semantics (fine in Java; use ord() in Python).
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic String funnyString(String s) { int n = s.length(); for (int i = 1; i < n; i++) { int forward = Math.abs(s.charAt(i) - s.charAt(i - 1)); int mirror = Math.abs(s.charAt(n - i) - s.charAt(n - i - 1));Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Comparing characters, not differences
'Funny' is about the GAPS between neighbours, not the letters. Comparing s[i] to r[i] tests whether the string is a palindrome — a different, stricter property.
Explore the code comparisonHide the code comparison
Comparing characters, not differences
'Funny' is about the GAPS between neighbours, not the letters. Comparing s[i] to r[i] tests whether the string is a palindrome — a different, stricter property.
Don't write this
r = s[::-1]
for i in range(len(s)):
if s[i] != r[i]:
return "Not Funny"
return "Funny"Write this instead
for i in range(1, len(s)):
if abs(ord(s[i]) - ord(s[i-1])) != abs(ord(s[len(s)-i]) - ord(s[len(s)-i-1])):
return "Not Funny"
return "Funny"2Dropping the absolute value
Reading neighbours from the reversed end flips the sign of every gap. Without abs() the forward gap +2 never equals the reverse gap −2, so almost no string is judged funny.
Explore the code comparisonHide the code comparison
Dropping the absolute value
Reading neighbours from the reversed end flips the sign of every gap. Without abs() the forward gap +2 never equals the reverse gap −2, so almost no string is judged funny.
Don't write this
int ds = s.charAt(i) - s.charAt(i - 1);
int dr = r.charAt(i) - r.charAt(i - 1);
if (ds != dr) return "Not Funny";Write this instead
int ds = Math.abs(s.charAt(i) - s.charAt(i - 1));
int dr = Math.abs(r.charAt(i) - r.charAt(i - 1));
if (ds != dr) return "Not Funny";3Wrong mirror index
When skipping the explicit reverse, the reverse's gap at step i is |s[n-i] - s[n-i-1]|. Using s[n-1-i] for a single character (instead of the pair) silently compares the wrong neighbours.
Explore the code comparisonHide the code comparison
Wrong mirror index
When skipping the explicit reverse, the reverse's gap at step i is |s[n-i] - s[n-i-1]|. Using s[n-1-i] for a single character (instead of the pair) silently compares the wrong neighbours.
Don't write this
mirror = abs(ord(s[n - 1 - i]) - ord(s[i - 1]))Write this instead
mirror = abs(ord(s[n - i]) - ord(s[n - i - 1]))Revise
Carry the pattern into the interview
Pattern to remember
Adjacent-difference sequence + symmetry check
Code pattern to memorize
n = len(s)
for i in 1 .. n-1:
if |s[i] - s[i-1]| != |s[n-i] - s[n-i-1]|:
return "Not Funny"
return "Funny"Rules to remember
- 1Compare absolute differences —
|s[i] − s[i−1]|, never the signed value. - 2You don't need to allocate
reverse(s): the reversed difference at stepiis|s[n−i] − s[n−i−1]|. - 3Index the original characters by their ASCII / code-point value, not the character itself.
- 4Loop
ifrom1ton−1; both the forward and mirrored differences are valid in that range. - 5Any single mismatch ends it as 'Not Funny'; survive all positions and it's 'Funny'.
Use this pattern when
- You must compare a string's adjacent-difference profile against its reverse
- The property is defined on gaps between neighbours, not the characters themselves
- You want to avoid building the reversed string and just mirror the index
- A symmetry / palindrome-of-differences check is hidden inside the prompt
Choose another pattern when
- The property uses the characters directly (not gaps) → compare characters, not differences
- Signed direction matters → don't take absolute value
- You must transform the string, not just answer yes/no → you may actually need the reverse
- Differences are over non-adjacent pairs → it's no longer a simple neighbour scan
Interview takeaway
A string is funny exactly when its sequence of adjacent absolute differences is a palindrome. Reversing the string reverses that difference sequence, so 'equal to its reverse's differences' is the same as 'the difference sequence reads the same both ways'. Mirror the index instead of building the reverse to keep it O(1) space.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternDifference-sequence symmetry. Translate a wordy string property into a concrete invariant — here the sequence of adjacent absolute differences — then notice that reversing the string reverses that sequence, so the test becomes 'is the difference sequence a palindrome?'. Mirroring the index (i ↔ n−i) reads the reverse's values straight off the original, trading O(n) space for O(1).
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Valid PalindromeSame mirror-index idea, but compare characters directly instead of their gaps.
- Funny String with signed differencesComing soonDrop the absolute value and ask which strings survive — a good 'why abs?' discussion.
- Longest Palindromic SubstringComing soonPalindrome detection scaled up — expand around centres instead of one full check.
- Mars ExplorationAnother adjacent-window string scan: count characters that deviate from the expected SOS pattern.