第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词 - 指南

news/2025/10/21 9:23:33/文章来源:https://www.cnblogs.com/tlnshuju/p/19154135

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词 - 指南

2025-10-21 09:20  tlnshuju  阅读(0)  评论(0)    收藏  举报

Q1、[中等] 矩阵中的幻方

1、题目描述

3 x 3 的幻方是一个填充有 19 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。

给定一个由整数组成的row x colgrid,其中有多少个 3 × 3 的 “幻方” 子矩阵?

注意:虽然幻方只能包含 1 到 9 的数字,但 grid 可以包含最多15的数字。

示例 1:

img

输入: grid = [[4,3,8,4],[9,5,1,9],[2,7,6,2]
输出: 1
解释:下面的子矩阵是一个 3 x 3 的幻方:而这一个不是:总的来说,在本示例所给定的矩阵中只有一个 3 x 3 的幻方子矩阵。

示例 2:

输入: grid = [[8]]
输出: 0

提示:

  • row == grid.length
  • col == grid[i].length
  • 1 <= row, col <= 10
  • 0 <= grid[i][j] <= 15
2、解题思路
  1. 问题分析

    • 需要遍历 grid 中所有可能的 3 × 3 子矩阵。
    • 对于每个子矩阵,检查它是否满足幻方的条件。
  2. 幻方的条件

    • 包含 19 的不同数字。
    • 每行、每列以及两条对角线的和都等于 15
  3. 优化

    • 幻方的中心必须是 5,因此可以提前过滤掉中心不是 5 的子矩阵。
  4. 算法设计

    • 遍历 grid 中所有可能的 3 × 3 子矩阵。
    • 对于每个子矩阵,检查是否满足幻方的条件。
    • 统计满足条件的子矩阵数量。
3、代码实现
C++
class Solution {public:// 检查一个 3x3 矩阵是否是幻方bool ismagic(array m) {int count[16] = {0}; // 用于统计数字出现的次数for (auto n : m) {// 检查数字是否在 1 到 9 之间且不重复if (n  9 || ++count[n] > 1) {return false;}}// 检查每行、每列以及两条对角线的和是否等于 15return m[0] + m[1] + m[2] == 15 && m[3] + m[4] + m[5] == 15 &&m[6] + m[7] + m[8] == 15 && m[0] + m[3] + m[6] == 15 &&m[1] + m[4] + m[7] == 15 && m[2] + m[5] + m[8] == 15 &&m[0] + m[4] + m[8] == 15 && m[2] + m[4] + m[6] == 15;}int numMagicSquaresInside(vector>& grid) {if (grid.size()  v; // 用于存储 3x3 子矩阵的元素int w = 0;for (int r = i; r < i + 3; r++) { // 提取 3x3 子矩阵for (int c = j; c < j + 3; c++) {v[w++] = grid[r][c];}}res += ismagic(v); // 检查是否是幻方
}
}
return res; // 返回幻方的数量
}
};
Java
class Solution {
// 检查一个 3x3 矩阵是否是幻方
private
boolean ismagic(
int[] m) {
int[] count =
new
int[16]
;
// 用于统计数字出现的次数
for (
int n : m) {
if (n <
1 || n >
9 || ++count[n] >
1
) {
// 检查数字是否在 1 到 9 之间且不重复
return false
;
}
}
// 检查每行、每列以及两条对角线的和是否等于 15
return m[0] + m[1] + m[2] == 15 && m[3] + m[4] + m[5] == 15 &&
m[6] + m[7] + m[8] == 15 && m[0] + m[3] + m[6] == 15 &&
m[1] + m[4] + m[7] == 15 && m[2] + m[5] + m[8] == 15 &&
m[0] + m[4] + m[8] == 15 && m[2] + m[4] + m[6] == 15
;
}
public
int numMagicSquaresInside(
int[][] grid) {
if (grid.length <
3 || grid[0].length <
3
) {
return 0
;
// 如果 grid 的大小小于 3x3,直接返回 0
}
int m = grid.length, n = grid[0].length;
int res = 0
;
// 记录幻方的数量
for (
int i = 0
; i < m - 2
; i++
) {
// 遍历所有可能的起始行
for (
int j = 0
; j < n - 2
; j++
) {
// 遍历所有可能的起始列
if (grid[i + 1][j + 1] != 5
) {
// 如果中心不是 5,跳过
continue
;
}
int[] v =
new
int[9]
;
// 用于存储 3x3 子矩阵的元素
int w = 0
;
for (
int r = i; r < i + 3
; r++
) {
// 提取 3x3 子矩阵
for (
int c = j; c < j + 3
; c++
) {
v[w++] = grid[r][c]
;
}
}
res += ismagic(v) ? 1 : 0
;
// 检查是否是幻方
}
}
return res;
// 返回幻方的数量
}
}
Python
class Solution:
def ismagic(self, m):
count = [0] * 16 # 用于统计数字出现的次数
for n in m:
if n <
1
or n >
9
or count[n] >
0: # 检查数字是否在 1 到 9 之间且不重复
return False
count[n] += 1
# 检查每行、每列以及两条对角线的和是否等于 15
return (
m[0] + m[1] + m[2] == 15
and m[3] + m[4] + m[5] == 15
and m[6] + m[7] + m[8] == 15
and m[0] + m[3] + m[6] == 15
and m[1] + m[4] + m[7] == 15
and m[2] + m[5] + m[8] == 15
and m[0] + m[4] + m[8] == 15
and m[2] + m[4] + m[6] == 15
)
def numMagicSquaresInside(self, grid):
if len(grid) <
3
or len(grid[0]
) <
3:
return 0 # 如果 grid 的大小小于 3x3,直接返回 0
m, n = len(grid)
, len(grid[0]
)
res = 0 # 记录幻方的数量
for i in range(m - 2
): # 遍历所有可能的起始行
for j in range(n - 2
): # 遍历所有可能的起始列
if grid[i + 1][j + 1] != 5: # 如果中心不是 5,跳过
continue
v = [
grid[r][c]
for r in range(i, i + 3
)
for c in range(j, j + 3
)
] # 提取 3x3 子矩阵
res += 1
if self.ismagic(v)
else 0 # 检查是否是幻方
return res # 返回幻方的数量

在这里插入图片描述

4、复杂度分析
  1. 时间复杂度

    • 遍历所有可能的 3 × 3 子矩阵:O((m−2)×(n−2))。
    • 检查每个子矩阵是否是幻方:O(1)。
    • 总时间复杂度:O((m−2)×(n−2))。
  2. 空间复杂度

    • 使用常数级别的额外空间,空间复杂度为 O(1)。

Q2、[中等] 钥匙和房间

1、题目描述

n 个房间,房间按从 0n - 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间。

当你进入一个房间,你可能会在里面找到一套 不同的钥匙,每把钥匙上都有对应的房间号,即表示钥匙可以打开的房间。你可以拿上所有钥匙去解锁其他房间。

给你一个数组 rooms 其中 rooms[i] 是你进入 i 号房间可以获得的钥匙集合。如果能进入 所有 房间返回 true,否则返回 false

示例 1:

输入:rooms = [[1],[2],[3],[]]
输出:true
解释:
我们从 0 号房间开始,拿到钥匙 1。
之后我们去 1 号房间,拿到钥匙 2。
然后我们去 2 号房间,拿到钥匙 3。
最后我们去了 3 号房间。
由于我们能够进入每个房间,我们返回 true。

示例 2:

输入:rooms = [[1,3],[3,0,1],[2],[0]]
输出:false
解释:我们不能进入 2 号房间。

提示:

  • n == rooms.length
  • 2 <= n <= 1000
  • 0 <= rooms[i].length <= 1000
  • 1 <= sum(rooms[i].length) <= 3000
  • 0 <= rooms[i][j] < n
  • 所有 rooms[i] 的值 互不相同
2、解题思路
  1. 问题分析

    • 房间和钥匙的关系可以看作是一个图,其中房间是节点,钥匙是边。
    • 0 号房间开始,通过钥匙逐步解锁其他房间。
    • 需要判断是否可以从 0 号房间访问到所有其他房间。
  2. 算法设计

    • 使用广度优先搜索(BFS)或深度优先搜索(DFS)遍历图。
    • 0 号房间开始,将所有可以访问的房间加入集合。
    • 最终检查集合的大小是否等于 n
  3. 优化

    • 使用 BFS 或 DFS 确保所有可达房间都被访问。
3、代码实现
C++
class Solution {public:bool canVisitAllRooms(vector>& rooms) {int n = rooms.size();       // 房间的数量unordered_set visited; // 记录已访问的房间queue q;               // BFS 队列q.push(0);                  // 从 0 号房间开始visited.insert(0);          // 标记 0 号房间为已访问while (!q.empty()) {       // BFS 过程int index = q.front(); // 取出当前房间q.pop();for (const auto& key : rooms[index]) { // 遍历当前房间的钥匙if (!visited.count(key)) {         // 如果钥匙对应的房间未被访问q.push(key);                   // 加入队列visited.insert(key);           // 标记为已访问}}
}
return visited.size() == n; // 判断是否访问了所有房间
}
};
class Solution {private:vector visited;int num;void dfs(vector>& rooms, int x) {visited[x] = true;num++;for (const auto& it : rooms[x]) {if (!visited[it]) {dfs(rooms, it);}}}public:bool canVisitAllRooms(vector>& rooms) {int n = rooms.size();num = 0;visited.resize(n);dfs(rooms, 0);return num == n;}};
Java
class Solution {
public
boolean canVisitAllRooms(List<
List<
Integer>
> rooms) {
int n = rooms.size(
)
;
// 房间的数量
Set<
Integer> visited =
new HashSet<
>(
)
;
// 记录已访问的房间
Queue<
Integer> q =
new LinkedList<
>(
)
;
// BFS 队列
q.offer(0
)
;
// 从 0 号房间开始
visited.add(0
)
;
// 标记 0 号房间为已访问
while (!q.isEmpty(
)
) {
// BFS 过程
int index = q.poll(
)
;
// 取出当前房间
for (
int key : rooms.get(index)
) {
// 遍历当前房间的钥匙
if (!visited.contains(key)
) {
// 如果钥匙对应的房间未被访问
q.offer(key)
;
// 加入队列
visited.add(key)
;
// 标记为已访问
}
}
}
return visited.size(
) == n;
// 判断是否访问了所有房间
}
}
Python
class Solution:
def canVisitAllRooms(self, rooms: List[List[int]]
) ->
bool:
n = len(rooms) # 房间的数量
visited = set(
) # 记录已访问的房间
q = deque(
) # BFS 队列
q.append(0
) # 从 0 号房间开始
visited.add(0
) # 标记 0 号房间为已访问
while q: # BFS 过程
index = q.popleft(
) # 取出当前房间
for key in rooms[index]: # 遍历当前房间的钥匙
if key not
in visited: # 如果钥匙对应的房间未被访问
q.append(key) # 加入队列
visited.add(key) # 标记为已访问
return len(visited) == n # 判断是否访问了所有房间

在这里插入图片描述

4、复杂度分析
  1. 时间复杂度
    • 每个房间和钥匙最多被访问一次,时间复杂度为 O*(*n+k),其中 n 是房间的数量,k 是钥匙的总数。
  2. 空间复杂度
    • 使用 visited 集合和队列 q,空间复杂度为 O(n)。

Q3、[中等] 将数组拆分成斐波那契序列

1、题目描述

给定一个数字字符串 num,比如 "123456579",我们可以将它分成「斐波那契式」的序列 [123, 456, 579]

形式上,斐波那契式 序列是一个非负整数列表 f,且满足:

  • 0 <= f[i] < 231 ,(也就是说,每个整数都符合 32 位 有符号整数类型)
  • f.length >= 3
  • 对于所有的0 <= i < f.length - 2,都有 f[i] + f[i + 1] = f[i + 2]

另外,请注意,将字符串拆分成小块时,每个块的数字一定不要以零开头,除非这个块是数字 0 本身。

返回从 num 拆分出来的任意一组斐波那契式的序列块,如果不能拆分则返回 []

示例 1:

输入:num = "1101111"
输出:[11,0,11,11]
解释:输出 [110,1,111] 也可以。

示例 2:

输入: num = "112358130"
输出: []
解释: 无法拆分。

示例 3:

输入:"0123"
输出:[]
解释:每个块的数字不能以零开头,因此 "01","2","3" 不是有效答案。

提示:

  • 1 <= num.length <= 200
  • num 中只含有数字
2、解题思路
  1. 问题分析

    • 需要将字符串 num 拆分成一个斐波那契式序列。
    • 序列中的每个整数必须满足 0 <= f[i] < 2^31
    • 序列的长度至少为 3,且满足斐波那契性质。
    • 拆分时,不能有前导零(除非是 0 本身)。
  2. 算法设计

    • 使用回溯法枚举所有可能的拆分方式。
    • 对于每个可能的拆分,检查是否满足斐波那契性质。
    • 如果找到满足条件的序列,则返回结果。
  3. 优化

    • 在回溯过程中,如果当前数字超过 2^31 - 1,则直接剪枝。

    • 如果当前数字不满足斐波那契性质,则剪枝。

3、代码实现
C++
class Solution {public:vector splitIntoFibonacci(string num) {vector list;                            // 用于存储斐波那契序列backtrack(list, num, num.length(), 0, 0, 0); // 调用回调函数return list;                                 // 返回结果}bool backtrack(vector& list, string num, int length, int index, long long sum, int prev) {if (index == length) {return list.size() >= 3; // 如果遍历完字符串序列且序列长度 >= 3, 返回 true}long long curr = 0; // 当前数字for (int i = index; i  index && num[index] == '0') {break; // 如果有前导零, 直接剪枝}curr = curr * 10 + (num[i] - '0'); // 计算当前数字if (curr > INT_MAX) {break; // 如果当前数字超过 2^31 - 1, 剪枝}if (list.size() >= 2) {if (curr  sum) {break; // 如果当前数字大于 sum,剪枝}}list.push_back(curr); // 将当前数字加入序列if (backtrack(list, num, length, i + 1, prev + curr, curr)) {return true;}list.pop_back(); // 回溯, 移除当前数字}return false; // 如果没有找到满足条件的序列, 返回 false}};
Java
class Solution {
public List<
Integer> splitIntoFibonacci(String num) {
List<
Integer> list =
new ArrayList<
>(
)
;
// 用于存储斐波那契序列
backtrack(list, num, num.length(
)
, 0
, 0
, 0
)
;
// 调用回溯函数
return list;
// 返回结果
}
private
boolean backtrack(List<
Integer> list, String num,
int length,
int index,
long sum,
long prev) {
if (index == length) {
return list.size(
) >= 3
;
// 如果遍历完字符串且序列长度 >= 3,返回 true
}
long curr = 0
;
// 当前数字
for (
int i = index; i < length; i++
) {
if (i > index && num.charAt(index) == '0'
) {
break
;
// 如果有前导零,直接剪枝
}
curr = curr * 10 + (num.charAt(i) - '0'
)
;
// 计算当前数字
if (curr >
Integer.MAX_VALUE
) {
break
;
// 如果当前数字超过 2^31 - 1,剪枝
}
if (list.size(
) >= 2
) {
if (curr < sum) {
continue
;
// 如果当前数字小于 sum,继续增加数字
}
else
if (curr > sum) {
break
;
// 如果当前数字大于 sum,剪枝
}
}
list.add((
int
) curr)
;
// 将当前数字加入序列
if (backtrack(list, num, length, i + 1
, prev + curr, curr)
) {
return true
;
// 如果找到满足条件的序列,返回 true
}
list.remove(list.size(
) - 1
)
;
// 回溯,移除当前数字
}
return false
;
// 如果没有找到满足条件的序列,返回 false
}
}
Python
class Solution:
def splitIntoFibonacci(self, num: str
) -> List[int]:
def backtrack(index, sum_val, prev, path):
if index == len(num):
return len(path) >= 3 # 如果遍历完字符串且序列长度 >= 3,返回 True
curr = 0 # 当前数字
for i in range(index, len(num)
):
if i > index and num[index] == "0":
break # 如果有前导零,直接剪枝
curr = curr * 10 + int(num[i]
) # 计算当前数字
if curr >
2**31 - 1:
break # 如果当前数字超过 2^31 - 1,剪枝
if len(path) >= 2:
if curr < sum_val:
continue # 如果当前数字小于 sum,继续增加数字
elif curr > sum_val:
break # 如果当前数字大于 sum,剪枝
path.append(curr) # 将当前数字加入序列
if backtrack(i + 1
, prev + curr, curr, path):
return True # 如果找到满足条件的序列,返回 True
path.pop(
) # 回溯,移除当前数字
return False # 如果没有找到满足条件的序列,返回 False
result = []
backtrack(0
, 0
, 0
, result)
return result

在这里插入图片描述

4、复杂度分析
  1. 时间复杂度

    • 最坏情况下,回溯的时间复杂度为 O(2n),其中 n 是字符串的长度。
    • 由于剪枝的存在,实际运行时间会大大减少。
  2. 空间复杂度

    • 使用递归栈和结果列表,空间复杂度为 O(n)。

Q4、[困难] 猜猜这个单词

1、题目描述

给你一个由 不同 字符串组成的单词列表 words ,其中 words[i] 长度均为 6words 中的一个单词将被选作秘密单词 secret

另给你一个辅助对象 Master ,你可以调用 Master.guess(word) 来猜单词,其中参数 word 长度为 6 且必须是 words 中的字符串。

Master.guess(word) 将会返回如下结果:

  • 如果 word 不是 words 中的字符串,返回 -1 ,或者
  • 一个整数,表示你所猜测的单词 word秘密单词secret 的准确匹配(值和位置同时匹配)的数目。

每组测试用例都会包含一个参数 allowedGuesses ,其中 allowedGuesses 是你可以调用 Master.guess(word) 的最大次数。

对于每组测试用例,在不超过允许猜测的次数的前提下,你应该调用 Master.guess 来猜出秘密单词。最终,你将会得到以下结果:

  • 如果你调用 Master.guess 的次数大于 allowedGuesses 所限定的次数或者你没有用 Master.guess 猜到秘密单词,则得到 "Either you took too many guesses, or you did not find the secret word."
  • 如果你调用 Master.guess 猜到秘密单词,且调用 Master.guess 的次数小于或等于 allowedGuesses ,则得到 "You guessed the secret word correctly."

生成的测试用例保证你可以利用某种合理的策略(而不是暴力)猜到秘密单词。

示例 1:

输入:secret = "acckzz", words = ["acckzz","ccbazz","eiowzz","abcczz"], allowedGuesses = 10
输出:You guessed the secret word correctly.
解释:
master.guess("aaaaaa") 返回 -1 ,因为 "aaaaaa" 不在 words 中。
master.guess("acckzz") 返回 6 ,因为 "acckzz" 是秘密单词 secret ,共有 6 个字母匹配。
master.guess("ccbazz") 返回 3 ,因为 "ccbazz" 共有 3 个字母匹配。
master.guess("eiowzz") 返回 2 ,因为 "eiowzz" 共有 2 个字母匹配。
master.guess("abcczz") 返回 4 ,因为 "abcczz" 共有 4 个字母匹配。
一共调用 5 次 master.guess ,其中一个为秘密单词,所以通过测试用例。

示例 2:

输入:secret = "hamada", words = ["hamada","khaled"], allowedGuesses = 10
输出:You guessed the secret word correctly.
解释:共有 2 个单词,且其中一个为秘密单词,可以通过测试用例。

提示:

  • 1 <= words.length <= 100
  • words[i].length == 6
  • words[i] 仅由小写英文字母组成
  • words 中所有字符串 互不相同
  • secret 存在于 words
  • 10 <= allowedGuesses <= 30
2、解题思路
  1. 问题分析
    • 需要从 words 中猜出秘密单词 secret
    • 每次调用 Master.guess(word) 会返回 wordsecret 的匹配数目。
    • 需要在允许的猜测次数内找到 secret
  2. 算法设计
    • 使用启发式方法,每次选择一个单词进行猜测,并根据返回的匹配数目缩小可能的候选单词范围。
    • 通过计算单词之间的匹配数目,选择能够最大程度减少候选单词数量的单词进行猜测。
  3. 优化
    • 使用预计算的匹配矩阵 H,其中 H[i][j] 表示 words[i]words[j] 的匹配数目。
    • 在每次猜测后,根据匹配数目过滤候选单词。
3、代码实现
C++
class Solution {private:vector> H; // 匹配矩阵, H[i][j] 表示 words[i] 和 words[j] 的匹配数目// 选择下一个猜测的单词int solve(vector& possible, vector& path) {if (possible.size()  ansgrp = possible;int ansguess = -1;// 遍历所有可能的猜测单词for (int guess = 0; guess > groups(7); // 根据匹配数目分组for (int j : possible) {if (j != guess) {groups[H[guess][j]].push_back(j);}}// 找到最大的组vector maxgroup = groups[0];for (int i = 0; i  maxgroup.size()) {maxgroup = groups[i];}}// 选择能够最小化最大组的猜测单词if (maxgroup.size() & words, Master& master) {int N = words.size();H = vector>(N, vector(N, 0)); // 初始化匹配矩阵for (int i = 0; i  possible; // 候选单词列表vector path;     // 已猜测的单词列表for (int i = 0; i  possible2; // 新的候选单词列表for (int j : possible) {if (H[guess][j] == matches) {possible2.push_back(j); // 根据匹配数目过滤候选单词}}possible = possible2;path.push_back(guess); // 将猜测单词加入已猜测列表}}};
Java
class Solution {
private
int[][] H
;
// 匹配矩阵,H[i][j] 表示 words[i] 和 words[j] 的匹配数目
// 选择下一个猜测的单词
private
int solve(List<
Integer> possible, List<
Integer> path) {
if (possible.size(
) <= 2
) {
return possible.get(0
)
;
// 如果候选单词数量 <= 2,直接返回第一个
}
List<
Integer> ansgrp = possible;
int ansguess = -1
;
// 遍历所有可能的猜测单词
for (
int guess = 0
; guess <
H.length; guess++
) {
if (!path.contains(guess)
) {
// 如果 guess 未被猜测过
List<
List<
Integer>
> groups =
new ArrayList<
>(7
)
;
for (
int i = 0
; i <
7
; i++
) {
groups.add(
new ArrayList<
>(
)
)
;
}
for (
int j : possible) {
if (j != guess) {
groups.get(H[guess][j]
).add(j)
;
// 根据匹配数目分组
}
}
// 找到最大的组
List<
Integer> maxgroup = groups.get(0
)
;
for (
int i = 0
; i <
7
; i++
) {
if (groups.get(i).size(
) > maxgroup.size(
)
) {
maxgroup = groups.get(i)
;
}
}
// 选择能够最小化最大组的猜测单词
if (maxgroup.size(
) < ansgrp.size(
)
) {
ansgrp = maxgroup;
ansguess = guess;
}
}
}
return ansguess;
}
public
void findSecretWord(String[] words, Master master) {
int N = words.length;
H =
new
int[N][N]
;
// 初始化匹配矩阵
for (
int i = 0
; i <
N
; i++
) {
for (
int j = i; j <
N
; j++
) {
int match = 0
;
for (
int k = 0
; k <
6
; k++
) {
if (words[i].charAt(k) == words[j].charAt(k)
) {
match++
;
}
}
H[i][j] = H[j][i] = match;
// 计算匹配数目
}
}
List<
Integer> possible =
new ArrayList<
>(
)
;
// 候选单词列表
List<
Integer> path =
new ArrayList<
>(
)
;
// 已猜测的单词列表
for (
int i = 0
; i <
N
; i++
) {
possible.add(i)
;
}
while (!possible.isEmpty(
)
) {
int guess = solve(possible, path)
;
// 选择下一个猜测单词
int matches = master.guess(words[guess]
)
;
// 调用 Master.guess
if (matches == words[0].length(
)
) {
return
;
// 如果猜中,直接返回
}
List<
Integer> possible2 =
new ArrayList<
>(
)
;
// 新的候选单词列表
for (
int j : possible) {
if (H[guess][j] == matches) {
possible2.add(j)
;
// 根据匹配数目过滤候选单词
}
}
possible = possible2;
path.add(guess)
;
// 将猜测单词加入已猜测列表
}
}
}
Python
class Solution:
def __init__(self):
self.H = [] # 匹配矩阵,H[i][j] 表示 words[i] 和 words[j] 的匹配数目
# 选择下一个猜测的单词
def solve(self, possible: List[int]
, path: List[int]
) ->
int:
if len(possible) <= 2:
return possible[0] # 如果候选单词数量 <= 2,直接返回第一个
ansgrp = possible
ansguess = -1
# 遍历所有可能的猜测单词
for guess in range(len(self.H)
):
if guess not
in path: # 如果 guess 未被猜测过
groups = [[]
for _ in range(7
)] # 根据匹配数目分组
for j in possible:
if j != guess:
groups[self.H[guess][j]].append(j)
# 找到最大的组
maxgroup = groups[0]
for i in range(7
):
if len(groups[i]
) >
len(maxgroup):
maxgroup = groups[i]
# 选择能够最小化最大组的猜测单词
if len(maxgroup) <
len(ansgrp):
ansgrp = maxgroup
ansguess = guess
return ansguess
def findSecretWord(self, words: List[str]
, master: "Master"
) ->
None:
N = len(words)
self.H = [[0] * N for _ in range(N)] # 初始化匹配矩阵
for i in range(N):
for j in range(i, N):
match = 0
for k in range(6
):
if words[i][k] == words[j][k]:
match += 1
self.H[i][j] = self.H[j][i] =
match # 计算匹配数目
possible = list(range(N)
) # 候选单词列表
path = [] # 已猜测的单词列表
while possible:
guess = self.solve(possible, path) # 选择下一个猜测单词
matches = master.guess(words[guess]
) # 调用 Master.guess
if matches == len(words[0]
):
return # 如果猜中,直接返回
possible = [
j for j in possible if self.H[guess][j] == matches
] # 根据匹配数目过滤候选单词
path.append(guess) # 将猜测单词加入已猜测列表

在这里插入图片描述

4、复杂度分析
  1. 时间复杂度
    • 时间复杂度:O(N2logN),其中 N 是单词的总数
  2. 空间复杂度
    • 空间复杂度:O(N2)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/941947.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

放大器保护机制的技术原理与实现策略

现代电子测量系统中,功率放大器和高压放大器通过多级保护机制(过流、过压、过温)确保设备稳定运行,具备自适应和智能控制功能在现代电子测量系统中,功率放大器和高压放大器作为关键信号调理设备,其保护机制的设计…

2025 年最新推荐!国内优质球墨铸铁管厂家排行榜出炉,涵盖自来水 / 给水 / 排污 / 污水用 / 消防 / 饮用水场景适用品牌

引言 当前国内基础设施建设对球墨铸铁管的需求持续增长,然而市场中品牌繁杂,部分产品存在质量不达标、性能不稳定等问题,导致采购方难以精准筛选出符合工程要求的优质品牌。尤其是在自来水输送、排污处理、消防供水…

2025 年球墨铸铁管件厂家最新推荐排行榜:市政 / 给排水 / 污水处理用优质厂家权威甄选

引言 在市政水利、建筑给排水、污水处理等核心基础设施领域,球墨铸铁管件的质量直接决定管网系统的安全与寿命。当前市场中,部分企业存在工艺落后、检测缺失等问题,导致产品抗腐蚀能力不足、使用寿命缩水,不仅增加…

中部地区-河南湖北湖南

湖北省地理 湖北省立体地形地貌、河流水系、气候特点分布图解 - 今日头条 地形地貌 地理位置与面积( 四至点和邻省:最东端:黄冈黄梅县(与安徽交界) 最西端:恩施利川市(与重庆接壤) 最南端:咸宁通城县(与湖南…

KafKa概念与安装 - 详解

KafKa概念与安装 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &qu…

MongoDB 聚合管道完全指南:数据分析的强大设备

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025 年最新防火涂料厂家排行榜:膨胀型 / 非膨胀型 / 厚型 / 薄型钢结构防火涂料优质企业最新推荐

引言 在建筑与工业安全领域,防火涂料是抵御火灾、守护生命财产安全的关键防线。当前市场上防火涂料品牌繁杂,部分产品存在防火性能不达标、环保性差、施工适配性不足等问题,加之行业技术迭代快,新品牌不断涌现,企…

2025 年南昌装修设计公司推荐:宿然设计,非营销型技术工作室,专注落地还原,提供全国纯设计与江西全案服务

当前南昌装修行业发展迅速,市场上装修公司数量众多,种类繁杂。不少消费者在选择装修公司时,常常面临难以抉择的困境,他们既希望找到能提供新颖设计方案的公司,又担忧设计无法顺利落地,难以实现理想中的居住空间效…

2025 年板材源头厂家最新推荐排行榜:聚焦 ENF 级环保与高品质,精选 6 家实力企业助您轻松选

引言 当前建材市场中,板材产品种类繁杂,质量与性能参差不齐,消费者在选购时常常面临诸多困扰:传统板材环保不达标,苯系物、甲醛等有害物质释放危害健康;部分产品易燃、施工复杂,不仅增加成本还延误工期;缺乏权…

优先队列运算符重载

方式 1 struct ab{int b,v,k;bool operator <(const ab &a)const{//代表前(v)与后(a.v)进行比较return v>a.v;} }; priority_queue<ab> q;方式 2 struct ab{int b,v,k;friend bool operator<(ab a,…

Mac INodeClient 异常连接 解决方案

起因 Mac 重启电脑 未关闭InodeClient 导致重启之后 连接卡死 反复重启卸载并没有启作用 解决方案 #!/bin/bash # 修复版清理脚本echo "=== 1. 强制终止所有iNode进程 ===" sudo pkill -9 iNode 2>/dev/n…

2025年GEO品牌推荐榜单:AI技术驱动的行业革新者

摘要 随着人工智能技术的快速发展,GEO行业正迎来前所未有的变革机遇。2025年,基于AI搜索优化和智能推荐算法的GEO服务已成为企业数字化转型的核心驱动力。本文通过对行业领先企业的深度分析,为寻求GEO服务的企业提供…

2025年GEO品牌推荐排行榜TOP10:AI技术驱动的行业新格局

摘要 随着人工智能技术在GEO领域的深度应用,2025年行业正迎来智能化转型的关键节点。本文基于技术实力、服务能力和市场口碑三大维度,对当前主流GEO服务商进行综合评估,为寻求加盟合作的企业提供权威参考。文末附行…

基于STM32F1x系列与JY901模块串口通信

一、硬件JY901引脚 STM32F103引脚 功能说明VCC 3.3V 电源供电GND GND 地线TX PA10 (USART1_RX) 接收数据RX PA9 (USART1_TX) 发送数据二、STM32串口配置代码(HAL库) // usart.c #include "stm32f1xx_hal.h"…

2025 年最新推荐防火涂料厂家排行榜:涵盖膨胀型、非膨胀型、室内外及超薄厚型钢结构防火涂料,助选优质产品

引言 在建筑行业持续发展的当下,防火安全是建筑安全的核心环节,防火涂料作为关键防护屏障,其质量直接关乎生命财产安全。当前市场中,部分防火涂料品牌为逐利降低成本,导致产品防火性能不达标、耐久性差,且品牌繁…

Hash与布隆过滤器

hash 函数 映射函数 Hash(key)=addr ;hash 函数可能会把两个或两个以上的不同 key 映射到同一地址,这种情况称之为冲突(或者 hash 碰撞)hash的优势计算速度快 强随机分布(等概率、均匀地分布在整个地址空间) m…

习题-归纳定义原理

习题1. 设\((b_1,b_2,\cdots)\)是实数的一个无穷序列。用归纳法定义它的和\(\sum_{k=1}^n b_k\)如下: \[\begin{align*}&\sum_{k=1}^n b_k = b_1\qquad\qquad\text{当}n=1,\\&\sum_{k=1}^n=(\sum_{k=1}^{n-1}…

对话式 AI 年度春晚:Convo AIRTE2025 全议程解锁

10 月 31 日 - 11 月 1 日北京悠唐皇冠假日酒店RTE2025 第十一届实时互联网大会两日全议程上线抢先预览,即刻收藏!阅读更多 Voice Agent 学习笔记:了解最懂 AI 语音的头脑都在思考什么

2025年安恒信息公司:深度解析AI与数据安全双轮驱动的技术护城河

引言:本文从“技术落地与标准制定”维度切入,拆解安恒信息如何在AI安全垂域大模型、隐私计算平台、国家级标准编制三条主线中形成可复用的技术护城河,为正在评估安全供应商的政企单位提供一份可落地的客观参考。 背…

C# Avalonia 16- Animation- SampleViewer - SimpleExample

C# Avalonia 16- Animation- SampleViewer - SimpleExampleSampleViewer.axaml代码<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xm…