200字
成语接龙
2025-11-26
2025-11-26

题目要求:

单词接龙,从指定索引的单词开始,每次接龙选择下一个单词的规则是:

  1. 下一个单词的首字母必须等于当前单词的尾字母。

  2. 如果有多个单词首字母相同,则选择长度最长的;如果长度也相同,则选择字典序最小的。

  3. 已经使用过的单词不能重复使用。

由于单词个数N最大为20,我们可以采用深度优先搜索(DFS)或者模拟的方式。
但注意,这里我们每次选择下一个单词时,只需要在所有未使用的单词中按照规则选择即可,因为规则是确定的,所以整个接龙过程是确定的。

思路:

  1. 读取起始索引K,单词个数N,以及单词列表。

  2. 将起始单词作为单词串的开始,并将其标记为已使用。

  3. 然后根据当前单词的尾字母,在未使用的单词中寻找所有首字母等于该尾字母的单词。

  4. 在这些单词中,按照规则(先比长度,长度相同比字典序)选择一个单词,将其加入单词串,并标记为已使用。

  5. 重复这个过程,直到没有可接的单词为止。

注意:规则中,当存在多个首字母相同的单词时,取长度最长的,如果长度也相等,则取字典序最小的。注意,字典序最小是指字符串比较中较小的那个。

由于每一步都是按照规则选取一个确定的单词,因此我们只需要循环直到无法选择为止。

但是,这里有一个注意点:可能同时有多个单词满足条件,但规则已经规定了如何选取,所以每次只选一个。

步骤:

  1. 读取输入。

  2. 初始化一个列表used,用于标记单词是否被使用。

  3. 从起始单词开始,将其加入结果字符串,并标记为已使用。

  4. 当前单词的尾字母为c,则在未使用的单词中查找首字母为c的单词,然后按照规则排序:先按长度降序,长度相同按字典序升序(因为要取字典序最小的,所以升序时第一个就是最小的)。

  5. 如果找到,则选择第一个单词(因为排序后第一个就是最长的,且字典序最小的),然后将其加入结果字符串,标记为已使用,并更新当前单词的尾字母。

  6. 重复步骤4-5,直到找不到符合条件的单词。

注意:排序规则:先按长度降序,如果长度相同,则按字典序升序。

例如:对于示例1,起始单词为"word",尾字母为'd',那么在以'd'开头的单词中,有"dd", "da", "dc", "dword", "d"(注意,起始单词已经使用,所以不能再用)。然后按照规则排序:
按长度:dword(长度5)> dd, da, dc, d(长度分别为2,2,2,1) -> 所以先选dword。
接着,当前单词变成dword,尾字母为'd',再从剩余的以'd'开头的单词中选:有"dd", "da", "dc", "d",同样按规则排序:dd, da, dc的长度都是2,d的长度为1,所以先考虑长度2的,然后按字典序:da, dc, dd(因为按字典序升序,da最小,所以先选da)。

但是,注意示例1的输出是"worddwordda",也就是说,接龙顺序是:word -> dword -> da。

因此,我们每次只选择一个单词,然后继续。

代码实现:

注意:起始单词已经使用,我们在循环开始前将起始单词标记为已使用,并放入结果字符串。

由于单词数量不多,我们可以直接模拟。

让我们按照步骤编写代码。

def input_contact():
    k = int(input().strip())
    n = int(input().strip())
    char_list = [input().strip() for _ in range(n)]
    return k, n, char_list


def init_game(k, n, char_list):
    """初始化游戏状态"""
    start_char = char_list[k]
    is_used = [False] * n
    is_used[k] = True
    result = [start_char]
    current_char = start_char
    return result, is_used, current_char


def find_candidates(is_used, current_char, char_list):
    """找到所有符合条件的候选单词"""
    last_char = current_char[-1]
    candidates = []

    for i, word in enumerate(char_list):
        if not is_used[i] and word[0] == last_char:
            candidates.append((word, i))  # 同时保存单词和索引

    return candidates


def select_best_candidate(candidates):
    """选择最佳候选单词"""
    if not candidates:
        return None, -1

    # 按长度降序,字典序升序排序
    candidates.sort(key=lambda x: (-len(x[0]), x[0]))

    # 返回最佳候选单词及其索引
    return candidates[0][0], candidates[0][1]


def find_long_str():
    """主函数:执行单词接龙"""
    k, n, char_list = input_contact()
    result, is_used, current_char = init_game(k, n, char_list)

    while True:
        # 找到所有候选单词
        candidates = find_candidates(is_used, current_char, char_list)

        # 选择最佳候选
        best_word, best_index = select_best_candidate(candidates)

        # 如果没有候选单词,结束游戏
        if best_word is None:
            break

        # 更新状态
        is_used[best_index] = True
        current_char = best_word
        result.append(best_word)

    return ''.join(result)


if __name__ == '__main__':
    result = find_long_str()
    print(result)

总结

选择贪心策略的原因:
1. 题目规则是确定性的,每一步都有唯一最优解
2. 不需要考虑所有可能路径,因为选择规则固定
3. 贪心算法的时间复杂度低,适合N≤20的数据规模
4. 如果要求最长可能链,才需要用回溯或DFS
我对题目的理解是:
1. 这是一个确定性的单词接龙,每一步的选择都是唯一的
2. 选择规则有明确优先级:
   - 第一优先级:首字母匹配前一个单词的尾字母
   - 第二优先级:在匹配的单词中选长度最长的
   - 第三优先级:长度相同时选字典序最小的
3. 每个单词只能使用一次
4. 输出是单词直接拼接,没有空格
时间复杂度:O(N²)
- 外层循环最多N次(每个单词用一次)
- 内层循环每次遍历N个单词找候选:O(N)
- 排序候选单词:O(MlogM),M≤N

空间复杂度:O(N)
- 存储使用标记和结果列表

成语接龙
作者
Shisuiyi
发表于
2025-11-26
License
CC BY-NC-SA 4.0

评论