青训营题目寻找独一无二的糖葫芦+珠子颜色去重题解

87 阅读5分钟

寻找独一无二的糖葫芦

1.问题描述

小C有n串长度为m的糖葫芦,每串糖葫芦可以用一个字符串表示。每个糖葫芦的甜度是所有字符甜度的总和,其中每个字符的甜度为该字符与 'a' 的差值。例如,字符 'a' 的甜度为 0,字符 'b' 的甜度为 1,依次类推,字符 'z' 的甜度为 25。

你需要帮助小C找到甜度最大的独一无二的糖葫芦。糖葫芦独一无二当且仅当它与其他n−1根糖葫芦都不同,且翻转后的字符串也不能与其他糖葫芦相同。例如,糖葫芦 "abc" 与 "cba" 视为相同的糖葫芦。

如果没有独一无二的糖葫芦,则返回0。

2.解题思路

2.1问题分析

  1. 甜度计算:每个字符的甜度是其与 'a' 的差值。例如,'a' 的甜度为 0,'b' 的甜度为 1,依此类推。
  2. 独一无二:一个糖葫芦是独一无二的,如果它与所有其他糖葫芦不同,并且其翻转后的字符串也与其他糖葫芦不同。
  3. 目标:找到甜度最大的独一无二的糖葫芦。如果没有这样的糖葫芦,返回 0。

2.2基本思路

  1. 字符串排序:将每个字符串按字符排序,这样可以方便地比较字符串是否相同。
  2. 翻转字符串:生成每个字符串的翻转字符串,并将其排序。
  3. 计数器:使用计数器统计每个排序后的字符串和其翻转字符串的出现次数。
  4. 甜度计算:计算每个字符串的甜度。
  5. 筛选独一无二的糖葫芦:筛选出出现次数为 1 的字符串,并找到其中甜度最大的。

2.3示例

以样例1为例:

  • 输入:n = 3, m = 3, strings = ["ccz", "cba", "zcc"]
  • 排序后的字符串:["ccz", "abc", "ccz"]
  • 翻转后的字符串:["zcc", "abc", "zcc"]
  • 计数器:{"ccz": 2, "abc": 1, "zcc": 2}
  • 甜度计算:"ccz" -> 5, "cba" -> 3, "zcc" -> 5
  • 结果:"cba" 是独一无二的,甜度为 3。

2.4代码

3.代码详解

  1. 字符串排序sorted_strings = [''.join(sorted(s)) for s in strings] 将每个字符串按字符排序,方便比较。
  2. 翻转字符串reversed_strings = [''.join(sorted(s[::-1])) for s in strings] 生成每个字符串的翻转字符串并排序。
  3. 计数器counter = Counter(sorted_strings + reversed_strings) 统计每个排序后的字符串和其翻转字符串的出现次数。
  4. 甜度计算sweetness = sum(ord(c) - ord('a') for c in s) 计算每个字符串的甜度。
  5. 筛选独一无二的糖葫芦if counter[''.join(sorted(s))] == 1 and counter[''.join(sorted(s[::-1]))] == 1 检查字符串及其翻转字符串是否独一无二,并更新最大甜度。

珠子颜色去重

1.问题描述

小S拥有一条由n颗珠子组成的手链,每颗珠子都有一个对应的颜色编号。她希望将手链上相同颜色的珠子进行去重,只保留每种颜色最后出现的那颗珠子,同时保持珠子原来的相对顺序。

例如,如果珠子的颜色编号是 [1, 2, 1, 3, 4, 2, 4, 4],去重后的珠子颜色应该是 [1, 3, 2, 4]

2.解题思路

2.1问题分析

我们需要处理一个包含颜色编号的列表,目标是去除重复的颜色,但只保留每种颜色最后出现的那一个,并且保持原有的相对顺序。

2.2基本思路

  1. 逆序遍历:从列表的末尾开始遍历,这样可以确保我们遇到的颜色是该颜色的最后一次出现。
  2. 使用集合记录已见过的颜色:当我们遇到一个颜色时,检查它是否已经出现在集合中。如果没有,则将其添加到结果列表中,并将其标记为已见过。
  3. 逆序结果:由于我们是逆序遍历的,最后的结果列表需要再逆序一次以恢复原来的相对顺序。

2.3示例

以输入 [1, 2, 1, 3, 4, 2, 4, 4] 为例:

  • 逆序遍历:[4, 4, 2, 4, 3, 1, 2, 1]

  • 记录已见过的颜色:

    • 遇到 4,未见过,添加到结果列表,标记为已见过。
    • 遇到 4,已见过,跳过。
    • 遇到 2,未见过,添加到结果列表,标记为已见过。
    • 遇到 4,已见过,跳过。
    • 遇到 3,未见过,添加到结果列表,标记为已见过。
    • 遇到 1,未见过,添加到结果列表,标记为已见过。
    • 遇到 2,已见过,跳过。
    • 遇到 1,已见过,跳过。
  • 结果列表:[4, 2, 3, 1]

  • 逆序结果列表:[1, 3, 2, 4]

2.4代码

def solution(n: int, a: list) -> list:
    seen = set()
    res = []
    for t in reversed(a):
        if t not in seen:
            seen.add(t)
            res.append(t)
    return list(reversed(res))

if __name__ == '__main__':
    print(solution(n = 8, a = [1, 2, 1, 3, 4, 2, 4, 4]) == [1, 3, 2, 4])
    print(solution(n = 5, a = [5, 5, 5, 5, 5]) == [5])
    print(solution(n = 6, a = [6, 1, 2, 6, 1, 2]) == [6, 1, 2])

3.代码详解

  1. 逆序遍历for t in reversed(a) 从列表的末尾开始遍历。
  2. 记录已见过的颜色seen = set() 使用集合来记录已经见过的颜色。
  3. 添加到结果列表if t not in seen: seen.add(t); res.append(t) 如果颜色未见过,则添加到结果列表中,并标记为已见过。
  4. 逆序结果列表return list(reversed(res)) 最后将结果列表逆序一次以恢复原来的相对顺序。 至此,完结撒花!