Array
Sorting
String
Description
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 .
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 <= 100
3 <= logs[i].length <= 100
All the tokens of logs[i]
are separated by a single space.
logs[i]
is guaranteed to have an identifier and at least one word after the identifier.
Solutions
Solution 1: Custom Sorting
We can use a custom sorting method to divide the logs into two categories: letter logs and digit logs.
For letter logs, we need to sort them according to the problem requirements, i.e., first by content and then by identifier.
For digit logs, we only need to maintain their original relative order.
The time complexity is \(O(n \times \log n)\) , and the space complexity is \(O(n)\) . Where \(n\) is the number of logs.
Python3 Java C++ Go TypeScript Rust
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 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 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 ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 class Solution {
public :
vector < string > reorderLogFiles ( vector < string >& logs ) {
stable_sort ( logs . begin (), logs . end (), []( const string & log1 , const string & log2 ) {
int idx1 = log1 . find ( ' ' );
int idx2 = log2 . find ( ' ' );
string id1 = log1 . substr ( 0 , idx1 );
string id2 = log2 . substr ( 0 , idx2 );
string content1 = log1 . substr ( idx1 + 1 );
string content2 = log2 . substr ( idx2 + 1 );
bool isLetter1 = isalpha ( content1 [ 0 ]);
bool isLetter2 = isalpha ( content2 [ 0 ]);
if ( isLetter1 && isLetter2 ) {
if ( content1 != content2 ) {
return content1 < content2 ;
}
return id1 < id2 ;
}
return isLetter1 > isLetter2 ;
});
return logs ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 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 ;
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 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
}
}
GitHub