Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given an array of logs. Each log is a space-delimited string of words, where the first word is the identifier.
There are two types of logs:
Reorder these logs so that:
Return the final order of the logs.
Example 1:
Input: logs = ["dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3 art zero"] Output: ["let1 art can","let3 art zero","let2 own kit dig","dig1 8 1 5 1","dig2 3 6"] Explanation: The letter-log contents are all different, so their ordering is "art can", "art zero", "own kit dig". The digit-logs have a relative order of "dig1 8 1 5 1", "dig2 3 6".
Example 2:
Input: logs = ["a1 9 2 3 1","g1 act car","zo4 4 7","ab1 off key dog","a8 act zoo"] Output: ["g1 act car","a8 act zoo","ab1 off key dog","a1 9 2 3 1","zo4 4 7"]
Constraints:
1 <= logs.length <= 1003 <= logs[i].length <= 100logs[i] are separated by a single space.logs[i] is guaranteed to have an identifier and at least one word after the identifier.Problem summary: You are given an array of logs. Each log is a space-delimited string of words, where the first word is the identifier. There are two types of logs: Letter-logs: All words (except the identifier) consist of lowercase English letters. Digit-logs: All words (except the identifier) consist of digits. Reorder these logs so that: The letter-logs come before all digit-logs. The letter-logs are sorted lexicographically by their contents. If their contents are the same, then sort them lexicographically by their identifiers. The digit-logs maintain their relative ordering. Return the final order of the logs.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array
["dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3 art zero"]
["a1 9 2 3 1","g1 act car","zo4 4 7","ab1 off key dog","a8 act zoo"]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #937: Reorder Data in Log Files
class Solution {
public String[] reorderLogFiles(String[] logs) {
Arrays.sort(logs, (log1, log2) -> {
String[] split1 = log1.split(" ", 2);
String[] split2 = log2.split(" ", 2);
boolean isLetter1 = Character.isLetter(split1[1].charAt(0));
boolean isLetter2 = Character.isLetter(split2[1].charAt(0));
if (isLetter1 && isLetter2) {
int cmp = split1[1].compareTo(split2[1]);
if (cmp != 0) {
return cmp;
}
return split1[0].compareTo(split2[0]);
}
return isLetter1 ? -1 : (isLetter2 ? 1 : 0);
});
return logs;
}
}
// Accepted solution for LeetCode #937: Reorder Data in Log Files
func reorderLogFiles(logs []string) []string {
sort.SliceStable(logs, func(i, j int) bool {
log1, log2 := logs[i], logs[j]
idx1 := strings.IndexByte(log1, ' ')
idx2 := strings.IndexByte(log2, ' ')
id1, content1 := log1[:idx1], log1[idx1+1:]
id2, content2 := log2[:idx2], log2[idx2+1:]
isLetter1 := 'a' <= content1[0] && content1[0] <= 'z'
isLetter2 := 'a' <= content2[0] && content2[0] <= 'z'
if isLetter1 && isLetter2 {
if content1 != content2 {
return content1 < content2
}
return id1 < id2
}
return isLetter1 && !isLetter2
})
return logs
}
# Accepted solution for LeetCode #937: Reorder Data in Log Files
class Solution:
def reorderLogFiles(self, logs: List[str]) -> List[str]:
def f(log: str):
id_, rest = log.split(" ", 1)
return (0, rest, id_) if rest[0].isalpha() else (1,)
return sorted(logs, key=f)
// Accepted solution for LeetCode #937: Reorder Data in Log Files
use std::cmp::Ordering;
impl Solution {
pub fn reorder_log_files(logs: Vec<String>) -> Vec<String> {
let mut logs = logs;
logs.sort_by(|log1, log2| {
let split1: Vec<&str> = log1.splitn(2, ' ').collect();
let split2: Vec<&str> = log2.splitn(2, ' ').collect();
let is_letter1 = split1[1].chars().next().unwrap().is_alphabetic();
let is_letter2 = split2[1].chars().next().unwrap().is_alphabetic();
if is_letter1 && is_letter2 {
let cmp = split1[1].cmp(split2[1]);
if cmp != Ordering::Equal {
return cmp;
}
return split1[0].cmp(split2[0]);
}
if is_letter1 {
Ordering::Less
} else if is_letter2 {
Ordering::Greater
} else {
Ordering::Equal
}
});
logs
}
}
// Accepted solution for LeetCode #937: Reorder Data in Log Files
function reorderLogFiles(logs: string[]): string[] {
return logs.sort((log1, log2) => {
const [id1, content1] = log1.split(/ (.+)/);
const [id2, content2] = log2.split(/ (.+)/);
const isLetter1 = isNaN(Number(content1[0]));
const isLetter2 = isNaN(Number(content2[0]));
if (isLetter1 && isLetter2) {
const cmp = content1.localeCompare(content2);
if (cmp !== 0) {
return cmp;
}
return id1.localeCompare(id2);
}
return isLetter1 ? -1 : isLetter2 ? 1 : 0;
});
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.