青训营题目:表现良好的时间段+题解

1 阅读4分钟

表现良好的时间段

1.问题描述

小M在分析员工的工作时间。他认为当某一天的工作小时数超过 8 小时时,这一天就是「劳累的一天」。他想找出最长的一段连续工作日,在这段时间内,「劳累的天数」严格大于「不劳累的天数」。你需要返回这个「表现良好时间段」的最大长度。

2.解题思路

2.1问题分析

  • 我们需要找到一个连续的子数组,其中「劳累的天数」严格大于「不劳累的天数」。
  • 「劳累的一天」定义为工作小时数超过8小时的天数。
  • 「不劳累的一天」定义为工作小时数不超过8小时的天数。

2.2基本思路

  1. 前缀和:我们可以将「劳累的一天」标记为1,「不劳累的一天」标记为-1,然后计算前缀和。
  2. 哈希表:使用哈希表记录每个前缀和第一次出现的位置。
  3. 查找最长子数组:通过前缀和的变化,找到满足条件的最大子数组长度。

2.3示例

以 hours = [9, 9, 6, 0, 6, 6, 9] 为例:

  • 转换为 [1, 1, -1, -1, -1, -1, 1]
  • 计算前缀和:[0, 1, 2, 1, 0, -1, -2, -1]
  • 使用哈希表记录每个前缀和第一次出现的位置。
  • 通过前缀和的变化,找到满足条件的最大子数组长度。

2.4代码

def solution(hours: list) -> int:
    # 将「劳累的一天」标记为1,「不劳累的一天」标记为-1
    hours = [1 if hour > 8 else -1 for hour in hours]
    
    # 前缀和
    prefix_sum = 0
    max_len = 0
    # 哈希表记录每个前缀和第一次出现的位置
    prefix_sum_map = {0: -1}
    
    for i, hour in enumerate(hours):
        prefix_sum += hour
        
        if prefix_sum > 0:
            max_len = i + 1
        elif prefix_sum - 1 in prefix_sum_map:
            max_len = max(max_len, i - prefix_sum_map[prefix_sum - 1])
        
        if prefix_sum not in prefix_sum_map:
            prefix_sum_map[prefix_sum] = i
    
    return max_len

if __name__ == '__main__':
    print(solution(hours=[9, 9, 6, 0, 6, 6, 9]) == 3)
    print(solution(hours=[6, 6, 6, 8]) == 0)
    print(solution(hours=[10, 10, 10, 0, 0, 9]) == 6)

3.代码详解

  1. 转换数组:将「劳累的一天」标记为1,「不劳累的一天」标记为-1。
  2. 前缀和计算:遍历数组,计算前缀和。
  3. 哈希表记录:使用哈希表记录每个前缀和第一次出现的位置。
  4. 查找最长子数组:通过前缀和的变化,找到满足条件的最大子数组长度。

数字字符串格式化

1.问题描述

小M需要将用户输入的不带千分位逗号的数字字符串转换为带千分位逗号的格式,并且保留小数部分。同时,输入的数字字符串前面可能会有无用的 0,这些也需要精简掉。

2.解题思路

2.1问题分析

  • 输入:一个不带千分位逗号的数字字符串,可能包含前导零和小数部分。
  • 输出:一个带千分位逗号的数字字符串,保留小数部分,去除前导零。

2.2 基本思路

  1. 去除前导零:使用 lstrip('0') 方法去除字符串前面的无用零。
  2. 分离整数和小数部分:使用 split('.') 方法将字符串分为整数部分和小数部分。
  3. 格式化整数部分:将整数部分反转,每三位插入一个逗号,然后再反转回来。
  4. 合并整数和小数部分:将格式化后的整数部分和小数部分重新合并。

2.3示例

  • 输入"1294512.12412"
  • 输出"1,294,512.12412"
  • 输入"0000123456789.99"
  • 输出"123,456,789.99"
  • 输入"987654321"
  • 输出"987,654,321"

2.4代码

def solution(s: str) -> str:
    # 去除前导零
    s = s.lstrip('0')
    
    # 分离整数和小数部分
    if '.' in s:
        integer_part, fractional_part = s.split('.')
    else:
        integer_part, fractional_part = s, ''
    
    # 格式化整数部分
    if integer_part:
        integer_part = ''.join(reversed(integer_part))  # 反转整数部分
        integer_part = ','.join(integer_part[i:i+3] for i in range(0, len(integer_part), 3))  # 每三位插入一个逗号
        integer_part = ''.join(reversed(integer_part))  # 再次反转回来
    
    # 合并整数和小数部分
    if fractional_part:
        return f"{integer_part}.{fractional_part}"
    else:
        return integer_part

if __name__ == '__main__':
    print(solution("1294512.12412") == '1,294,512.12412')
    print(solution("0000123456789.99") == '123,456,789.99')
    print(solution("987654321") == '987,654,321')

3.代码详解

3.1 去除前导零

使用 lstrip('0') 方法去除字符串 s 前面的所有 0

3.2 分离整数和小数部分

  • 如果字符串 s 中包含小数点 .,则使用 split('.') 方法将字符串分为整数部分 integer_part 和小数部分 fractional_part
  • 如果字符串 s 中不包含小数点 .,则整数部分为 s,小数部分为空字符串 ''

格式化整数部分

  • 首先将整数部分 integer_part 反转。
  • 然后使用列表推导式和 join 方法,每三位插入一个逗号。
  • 最后再次反转整数部分,得到格式化后的整数部分。

合并整数和小数部分

  • 如果小数部分 fractional_part 不为空,则将格式化后的整数部分和小数部分用小数点 . 连接起来。
  • 如果小数部分为空,则直接返回格式化后的整数部分。

至此,完结撒花!