LeetCode #3734 — HARD

Lexicographically Smallest Palindromic Permutation Greater Than Target

Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.

Solve on LeetCode
The Problem

Problem Statement

You are given two strings s and target, each of length n, consisting of lowercase English letters.

Return the lexicographically smallest string that is both a palindromic permutation of s and strictly greater than target. If no such permutation exists, return an empty string.

Example 1:

Input: s = "baba", target = "abba"

Output: "baab"

Explanation:

  • The palindromic permutations of s (in lexicographical order) are "abba" and "baab".
  • The lexicographically smallest permutation that is strictly greater than target is "baab".

Example 2:

Input: s = "baba", target = "bbaa"

Output: ""

Explanation:

  • The palindromic permutations of s (in lexicographical order) are "abba" and "baab".
  • None of them is lexicographically strictly greater than target. Therefore, the answer is "".

Example 3:

Input: s = "abc", target = "abb"

Output: ""

Explanation:

s has no palindromic permutations. Therefore, the answer is "".

Example 4:

Input: s = "aac", target = "abb"

Output: "aca"

Explanation:

  • The only palindromic permutation of s is "aca".
  • "aca" is strictly greater than target. Therefore, the answer is "aca".

Constraints:

  • 1 <= n == s.length == target.length <= 300
  • s and target consist of only lowercase English letters.
Patterns Used

Roadmap

  1. Brute Force Baseline
  2. Core Insight
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Code
  6. Interactive Study Demo
  7. Complexity Analysis
Step 01

Brute Force Baseline

Problem summary: You are given two strings s and target, each of length n, consisting of lowercase English letters. Return the lexicographically smallest string that is both a palindromic permutation of s and strictly greater than target. If no such permutation exists, return an empty string.

Baseline thinking

Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.

Pattern signal: Two Pointers

Example 1

"baba"
"abba"

Example 2

"baba"
"bbaa"

Example 3

"abc"
"abb"
Step 02

Core Insight

What unlocks the optimal approach

  • A palindromic permutation exists only if at most one character has an odd count (for odd-length strings) or all counts are even (for even-length strings).
  • Focus on constructing the first half of the palindrome. The second half is determined by mirroring.
  • To be lexicographically greater than target, the first half must be greater than or equal to target's first half, with careful handling of the middle character for odd-length strings.
  • Use a backtracking approach or greedy selection for each position in the first half, trying the smallest available character that can still produce a valid palindrome.
  • After building the first half, mirror it (and add the middle character if needed) to form the full palindrome and verify it is strictly greater than target.
Interview move: turn each hint into an invariant you can check after every iteration/recursion step.
Step 03

Algorithm Walkthrough

Iteration Checklist

  1. Define state (indices, window, stack, map, DP cell, or recursion frame).
  2. Apply one transition step and update the invariant.
  3. Record answer candidate when condition is met.
  4. Continue until all input is consumed.
Use the first example testcase as your mental trace to verify each transition.
Step 04

Edge Cases

Minimum Input
Single element / shortest valid input
Validate boundary behavior before entering the main loop or recursion.
Duplicates & Repeats
Repeated values / repeated states
Decide whether duplicates should be merged, skipped, or counted explicitly.
Extreme Constraints
Largest constraint values
Re-check complexity target against constraints to avoid time-limit issues.
Invalid / Corner Shape
Empty collections, zeros, or disconnected structures
Handle special-case structure before the core algorithm path.
Step 05

Full Annotated Code

Source-backed implementations are provided below for direct study and interview prep.

// Accepted solution for LeetCode #3734: Lexicographically Smallest Palindromic Permutation Greater Than Target
// Auto-generated Java example from go.
class Solution {
    public void exampleSolution() {
    }
}
// Reference (go):
// // Accepted solution for LeetCode #3734: Lexicographically Smallest Palindromic Permutation Greater Than Target
// package main
// 
// import (
// 	"slices"
// 	"strings"
// )
// 
// // https://space.bilibili.com/206214
// func lexPalindromicPermutation1(s, target string) string {
// 	left := make([]int, 26)
// 	for _, b := range s {
// 		left[b-'a']++
// 	}
// 	valid := func() bool {
// 		for _, c := range left {
// 			if c < 0 {
// 				return false
// 			}
// 		}
// 		return true
// 	}
// 
// 	midCh := ""
// 	for i, c := range left {
// 		if c%2 == 0 {
// 			continue
// 		}
// 		// s 不能有超过一个字母出现奇数次
// 		if midCh != "" {
// 			return ""
// 		}
// 		// 记录填在正中间的字母
// 		midCh = string('a' + byte(i))
// 		left[i]--
// 	}
// 
// 	n := len(s)
// 	// 先假设答案左半与 t 的左半(不含正中间)相同
// 	for _, b := range target[:n/2] {
// 		left[b-'a'] -= 2
// 	}
// 
// 	if valid() {
// 		// 特殊情况:把 target 左半翻转到右半,能否比 target 大?
// 		leftS := target[:n/2]
// 		tmp := []byte(leftS)
// 		slices.Reverse(tmp)
// 		rightS := midCh + string(tmp)
// 		if rightS > target[n/2:] { // 由于左半是一样的,所以只需比右半
// 			return leftS + rightS
// 		}
// 	}
// 
// 	for i := n/2 - 1; i >= 0; i-- {
// 		b := target[i] - 'a'
// 		left[b] += 2  // 撤销消耗
// 		if !valid() { // [0,i-1] 无法做到全部一样
// 			continue
// 		}
// 
// 		// 把 target[i] 增大到 j
// 		for j := b + 1; j < 26; j++ {
// 			if left[j] == 0 {
// 				continue
// 			}
// 
// 			// 找到答案(下面的循环在整个算法中只会跑一次)
// 			left[j] -= 2
// 			ans := []byte(target[:i+1])
// 			ans[i] = 'a' + j
// 
// 			// 中间可以随便填
// 			for k, c := range left {
// 				ch := string('a' + byte(k))
// 				ans = append(ans, strings.Repeat(ch, c/2)...)
// 			}
// 
// 			// 镜像翻转
// 			rightS := slices.Clone(ans)
// 			slices.Reverse(rightS)
// 			ans = append(ans, midCh...)
// 			ans = append(ans, rightS...)
// 
// 			return string(ans)
// 		}
// 		// 增大失败,继续枚举
// 	}
// 	return ""
// }
// 
// func lexPalindromicPermutation(s, target string) string {
// 	left := make([]int, 26)
// 	for _, b := range s {
// 		left[b-'a']++
// 	}
// 
// 	midCh := ""
// 	for i, c := range left {
// 		if c%2 == 0 {
// 			continue
// 		}
// 		// s 不能有超过一个字母出现奇数次
// 		if midCh != "" {
// 			return ""
// 		}
// 		// 记录填在正中间的字母
// 		midCh = string('a' + byte(i))
// 		left[i]--
// 	}
// 
// 	n := len(s)
// 	// 先假设答案左半与 t 的左半(不含正中间)相同
// 	for _, b := range target[:n/2] {
// 		left[b-'a'] -= 2
// 	}
// 
// 	neg, leftMax := 0, byte(0)
// 	for i, cnt := range left {
// 		if cnt < 0 {
// 			neg++ // 统计 left 中的负数个数
// 		} else if cnt > 0 {
// 			leftMax = max(leftMax, byte(i)) // 剩余可用字母的最大值
// 		}
// 	}
// 
// 	if neg == 0 {
// 		// 特殊情况:把 target 左半翻转到右半,能否比 target 大?
// 		leftS := target[:n/2]
// 		tmp := []byte(leftS)
// 		slices.Reverse(tmp)
// 		rightS := midCh + string(tmp)
// 		if rightS > target[n/2:] { // 由于左半是一样的,所以只需比右半
// 			return leftS + rightS
// 		}
// 	}
// 
// 	for i := n/2 - 1; i >= 0; i-- {
// 		b := target[i] - 'a'
// 		left[b] += 2 // 撤销消耗
// 
// 		if left[b] == 0 {
// 			neg--
// 		} else if left[b] == 2 {
// 			leftMax = max(leftMax, b)
// 		}
// 
// 		// left 有负数 or 没有大于 target[i] 的字母
// 		if neg > 0 || leftMax <= b {
// 			continue
// 		}
// 
// 		// 找到答案(下面的循环在整个算法中只会跑一次)
// 		j := b + 1
// 		for left[j] == 0 {
// 			j++
// 		}
// 
// 		// 把 target[i] 和 target[n-1-i] 增大到 j
// 		left[j] -= 2
// 		ans := []byte(target[:i+1])
// 		ans[i] = 'a' + j
// 
// 		// 中间可以随便填
// 		for k, c := range left {
// 			ch := string('a' + byte(k))
// 			ans = append(ans, strings.Repeat(ch, c/2)...)
// 		}
// 
// 		// 镜像翻转
// 		rightS := slices.Clone(ans)
// 		slices.Reverse(rightS)
// 		ans = append(ans, midCh...)
// 		ans = append(ans, rightS...)
// 
// 		return string(ans)
// 	}
// 	return ""
// }
Step 06

Interactive Study Demo

Use this to step through a reusable interview workflow for this problem.

Press Step or Run All to begin.
Step 07

Complexity Analysis

Time
O(n)
Space
O(1)

Approach Breakdown

BRUTE FORCE
O(n²) time
O(1) space

Two nested loops check every pair of elements. The outer loop picks one element, the inner loop scans the rest. For n elements that is n × (n−1)/2 comparisons = O(n²). No extra memory — just two loop variables.

TWO POINTERS
O(n) time
O(1) space

Each pointer traverses the array at most once. With two pointers moving inward (or both moving right), the total number of steps is bounded by n. Each comparison is O(1), giving O(n) overall. No auxiliary data structures are needed — just two index variables.

Shortcut: Two converging pointers on sorted data → O(n) time, O(1) space.
Coach Notes

Common Mistakes

Review these before coding to avoid predictable interview regressions.

Moving both pointers on every comparison

Wrong move: Advancing both pointers shrinks the search space too aggressively and skips candidates.

Usually fails on: A valid pair can be skipped when only one side should move.

Fix: Move exactly one pointer per decision branch based on invariant.