Given a string s, print all permutations of s whose letters appear in non-decreasing order when compared case-insensitively (i.e., for every adjacent pair a,b in the permutation, tolower(a) <= tolower(b)). We call such permutations well-ordered.
Method 1 — generate all permutations and filter by the well-ordered predicate (simple, easy to implement).
Method 2 — constructive backtracking that enforces the non-decreasing condition while building the permutation (more efficient since it prunes invalid partial permutations early).
Generate every permutation of the characters in s, then check whether the permutation is well-ordered by comparing adjacent characters case-insensitively. This is straightforward but does unnecessary work when many permutations fail the predicate.
import java.util.*;
classSolution {
public List<String>wellOrderedPermutations(String s) {
if (s ==null|| s.isEmpty()) return Collections.emptyList();
List<String> ans =new ArrayList<>();
char[] arr = s.toCharArray();
dfs(arr, 0, ans);
Collections.sort(ans);
returnnew ArrayList<>(new LinkedHashSet<>(ans));
}
privatevoiddfs(char[] arr, int i, List<String> ans) {
if (i == arr.length) {
if (isWell(arr)) ans.add(new String(arr));
return;
}
for (int j = i; j < arr.length; j++) {
swap(arr, i, j);
dfs(arr, i+1, ans);
swap(arr, i, j);
}
}
privatebooleanisWell(char[] a) {
for (int i = 0; i + 1 < a.length; i++) {
if (Character.toLowerCase(a[i]) > Character.toLowerCase(a[i+1])) returnfalse;
}
returntrue;
}
privatevoidswap(char[] a, int i, int j) {
char t = a[i]; a[i]= a[j]; a[j]= t;
}
}
classSolution {
funwellOrderedPermutations(s: String): List<String> {
if (s.isEmpty()) return emptyList()
val ans = mutableSetOf<String>()
val arr = s.toCharArray()
fundfs(i: Int) {
if (i == arr.size) {
if (isWell(arr)) ans.add(String(arr))
return }
for (j in i until arr.size) {
val tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp
dfs(i+1)
val tmp2 = arr[i]; arr[i] = arr[j]; arr[j] = tmp2
}
}
dfs(0)
return ans.toList().sorted()
}
privatefunisWell(a: CharArray): Boolean {
for (i in0 until a.size - 1) if (a[i].lowercaseChar() > a[i+1].lowercaseChar()) returnfalsereturntrue }
}
When building permutations, maintain the case-insensitive last character chosen and only place a character next if its lowercase is >= the previous lowercase. This prunes many branches early since any violation disqualifies the partial permutation.