重新排列日志文件

标签: 数组 字符串 排序

难度: Medium

给你一个日志数组 logs。每条日志都是以空格分隔的字串,其第一个字为字母与数字混合的 标识符

有两种不同类型的日志:

  • 字母日志:除标识符之外,所有字均由小写字母组成
  • 数字日志:除标识符之外,所有字均由数字组成

请按下述规则将日志重新排序:

  • 所有 字母日志 都排在 数字日志 之前。
  • 字母日志 在内容不同时,忽略标识符后,按内容字母顺序排序;在内容相同时,按标识符排序。
  • 数字日志 应该保留原来的相对顺序。

返回日志的最终顺序。

 

示例 1:

输入:logs = ["dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3 art zero"]
输出:["let1 art can","let3 art zero","let2 own kit dig","dig1 8 1 5 1","dig2 3 6"]
解释:
字母日志的内容都不同,所以顺序为 "art can", "art zero", "own kit dig" 。
数字日志保留原来的相对顺序 "dig1 8 1 5 1", "dig2 3 6" 。

示例 2:

输入:logs = ["a1 9 2 3 1","g1 act car","zo4 4 7","ab1 off key dog","a8 act zoo"]
输出:["g1 act car","a8 act zoo","ab1 off key dog","a1 9 2 3 1","zo4 4 7"]

 

提示:

  • 1 <= logs.length <= 100
  • 3 <= logs[i].length <= 100
  • logs[i] 中,字与字之间都用 单个 空格分隔
  • 题目数据保证 logs[i] 都有一个标识符,并且在标识符之后至少存在一个字

Submission

运行时间: 21 ms

内存: 16.1 MB

class Solution:
    def reorderLogFiles(self, logs: List[str]) -> List[str]:
        letter_logs = []  # 存放字母日志
        number_logs = []  # 存放数字日志
        letter_logs2 = []
        for log in logs:
            parts = log.split(" ")  # 分割为标识符和内容
            # 检查内容是否为数字
            if parts[1].isdigit():
                number_logs.append(log)
            else:
                letter_logs.append(log)

        # 对字母日志按内容排序,如果内容相同则按标识符排序
        for letter_log in letter_logs:
            parts2 = letter_log.split(" ", 1)  # 分成标识和内容两部分
            letter_logs2.append(parts2)
        letter_logs2.sort(key=lambda x: (x[1], x[0]))

        # 将分割的日志重新组合为字符串
        letter_logs2 = [' '.join(log) for log in letter_logs2]

        # 合并字母日志和数字日志
        return letter_logs2 + number_logs



Explain

题解首先将日志分为字母日志和数字日志两类。字母日志根据其内容先排序,若内容相同则根据标识符排序;数字日志则保持原始顺序。最终输出时,将排序后的字母日志与未改变顺序的数字日志合并输出。

时间复杂度: O(n log n)

空间复杂度: O(n)

class Solution:
    def reorderLogFiles(self, logs: List[str]) -> List[str]:
        letter_logs = []  # 存放字母日志
        number_logs = []  # 存放数字日志
        letter_logs2 = []
        for log in logs:
            parts = log.split(" ")  # 分割为标识符和内容
            # 检查内容是否为数字
            if parts[1].isdigit():
                number_logs.append(log)
            else:
                letter_logs.append(log)

        # 对字母日志按内容排序,如果内容相同则按标识符排序
        for letter_log in letter_logs:
            parts2 = letter_log.split(" ", 1)  # 分成标识和内容两部分
            letter_logs2.append(parts2)
        letter_logs2.sort(key=lambda x: (x[1], x[0]))

        # 将分割的日志重新组合为字符串
        letter_logs2 = [' '.join(log) for log in letter_logs2]

        # 合并字母日志和数字日志
        return letter_logs2 + number_logs

Explore

为确保正确分割日志,应使用`split`方法时限定`maxsplit`参数为1。这样,即使日志内容中包含空格,`split(' ', 1)`也只会在第一个空格处分割字符串,从而将日志分为标识符和内容两部分。标识符为第一部分,剩余的全部内容(包括可能的空格)将作为第二部分。

使用`isdigit()`函数时,应确保仅对日志的内容部分(非标识符)进行检查。在题解中,通过`split(' ')`后,`parts[1]`指的是内容的第一个元素。如果日志正确地按照格式分割,这种方法通常有效。但更保险的方式是使用`split(' ', 1)`并检查返回数组的第二个元素(即内容部分)。这样可以避免误将标识符当作内容处理。

TimSort是Python内置排序方法`sort()`的实现基础,它是一种稳定的排序算法,特别适用于部分已排序的数据。TimSort的优势在于它结合了归并排序和插入排序的优点,具有很好的最坏情况时间复杂度O(n log n)。对于字母日志这种可能具有部分顺序的数据,TimSort能够提供高效且稳定的性能。

在重新组合时,一个边界情况是日志内容完全为空。按照`split(' ', 1)`方法,如果日志仅包含标识符而无内容,则分割结果将有两个元素,第二个元素为空字符串。在排序和重新组合时,这种情况应被保留而不被丢弃,确保日志的完整性。此外,如果日志列表本身为空或所有日志都是数字日志,确保代码能正确处理这些情况,避免运行时错误。