玩玩算法题——Episode 2
Leetcode每日一题:最大字符串匹配数目
题干如下:
给你一个下标从 0 开始的数组 words ,数组中包含互不相同的字符串。
如果字符串 words[i]
与字符串 words[j]
满足以下条件,我们称它们可以匹配:
字符串 words[i]
等于 words[j]
的反转字符串。
0 <= i < j < words.length
请你返回数组 words
中的 最大 匹配数目。
注意,每个字符串最多匹配一次。
示例 1:
输入:words = ["cd","ac","dc","ca","zz"]
输出:2
解释:在此示例中,我们可以通过以下方式匹配 2 对字符串:
- 我们将第 0 个字符串与第 2 个字符串匹配,因为 word[0] 的反转字符串是 "dc" 并且等于 words[2]。
- 我们将第 1 个字符串与第 3 个字符串匹配,因为 word[1] 的反转字符串是 "ca" 并且等于 words[3]。
可以证明最多匹配数目是 2 。
示例 2:
输入:words = ["ab","ba","cc"]
输出:1
解释:在此示例中,我们可以通过以下方式匹配 1 对字符串:
- 我们将第 0 个字符串与第 1 个字符串匹配,因为 words[1] 的反转字符串 "ab" 与 words[0] 相等。
可以证明最多匹配数目是 1 。
示例 3:
输入:words = ["aa","ab"]
输出:0
解释:这个例子中,无法匹配任何字符串。
提示:
1 <= words.length <= 50
words[i].length == 2
words
包含的字符串互不相同。
words[i]
只包含小写英文字母。
Star Rating: 2.68(个人观点)
SR转换:
Leetcode简单 -> 约等于1~2星难度
Leetcode普通 -> 约等于3~4星难度
Leetcode困难 -> 约等于5~6星难度
首先,仍然有一种很暴力的解法,复杂度是O(n^2)
,,也就是固定一个字符串,尝试去找另一个字符串。
但是,这种算法的效率是很低的,因此我们需要想一个更好的方法
我们会发现:
(1)由于words不能包含相同的字符串,因此两个字母相同的字符串不能和任何其他字符串匹配。
Leetcode的题比较偏向数据结构的应用,所以我们要尽量往这个方向去思考...不过对于这个题来说仍然想不到任何思路。
但是我们可以先写一下BF的方法:
class Solution(object): def maximumNumberOfStringPairs(self, words): """ :type words: List[str] :rtype: int """ count = 0 for i in range (len(words)): if words[i][0] == words[i][1]: continue for j in range (len(words)): if words[i][0] == words[j][1] and words[i][1] == words[j][0]: count += 1 return count // 2 #每一对匹配字符串计算了两次,所以返回的值要除以2
不过...有没有更好的方法呢?
能够正确提交,32ms(35.71% defeated) and 13.21MB(7.14% defeated)
Current: 23pp(New!)
Overall: 124pp(+19pp)
现在我们思考一下,有没有更好的方法呢?
ChatGPT给出了一个能够拿到34pp的方法:
这个问题可以通过使用字典(哈希表)来提高效率。我们可以将每个字符串的反转形式作为键,然后统计每个反转形式的出现次数。在遍历过程中,如果当前字符串的反转形式已经在字典中出现过,则说明可以进行匹配,匹配的次数就是该反转形式在字典中的出现次数。最后取所有匹配次数的和即为最大匹配数目。
以下是相应的代码:(ChatGPT一开始产生的代码是错的,所以我们又稍微改了一点)
from collections import defaultdict class Solution(object): def maximumNumberOfStringPairs(self, words): """ :type words: List[str] :rtype: int """ reverse_counts = defaultdict(int) for word in words: if word[0] != word[1]: reverse_form = word[1] + word[0] if reverse_counts[reverse_form] == 1: reverse_counts[reverse_form] += 1 else: reverse_counts[word[0] + word[1]] += 1 # 这样精心设计以后,一对匹配的字符串,会在reverse_counts中产生一个值为2的键 max_matches = sum(count for count in reverse_counts.values() if count % 2 == 0) // 2 #找到值为2的键的总个数 return max_matches
这种方法的时间复杂度为 O(n),其中 n 是字符串数组的长度。我们通过一次遍历统计了每个反转形式的出现次数,然后计算匹配次数的和。因为字典的查找操作是 O(1) 的平均复杂度,所以总体上是线性时间的。
defaultdict
是 Python 中的一个特殊字典,它可以在创建时指定默认值的类型,当访问一个不存在的键时,会返回默认值。在这个问题中,我们使用 defaultdict(int)
创建了一个默认值为 0 的字典,即如果某个键不存在,则返回 0。
在上述代码中,reverse_counts
是一个字典,它的键是字符串的反转形式,值是该反转形式出现的次数。由于我们在创建 defaultdict(int)
时指定了默认值为 0,所以当访问一个不存在的键时,会返回 0。
这样做的好处是,在遍历 words
数组时,我们无需判断每个键是否存在,直接通过 reverse_counts[reverse_form]
就能获取到相应的值,而且不存在的键会自动被初始化为 0。
使用 defaultdict
可以简化代码,使其更加清晰和简洁。
Yes~ 性能有了显著提升 11ms(100.00% Defeated)和11.54MB(100.00% Defeated)
Current: 34pp(+11pp)
Overall: 135pp(+11pp)
Leetcode 1237. 找出给定方程的正整数解
Star Rating: 3.62
题目描述如下:
给你一个函数 f(x, y) 和一个目标结果 z,函数公式未知,请你计算方程 f(x,y) == z 所有可能的正整数数对 x 和 y。满足条件的结果数对可以按任意顺序返回。
尽管函数的具体式子未知,但它是单调递增函数,也就是说:
f(x, y) < f(x + 1, y)
f(x, y) < f(x, y + 1)
函数接口定义如下:
interface CustomFunction {
public:
// Returns some positive integer f(x, y) for two positive integers x and y based on a formula.
int f(int x, int y);
};
你的解决方案将按如下规则进行评判:
判题程序有一个由 CustomFunction
的 9 种实现组成的列表,以及一种为特定的 z 生成所有有效数对的答案的方法。
判题程序接受两个输入:function_id
(决定使用哪种实现测试你的代码)以及目标结果 z
。
判题程序将会调用你实现的 findSolution
并将你的结果与答案进行比较。
如果你的结果与答案相符,那么解决方案将被视作正确答案,即 Accepted 。
示例 1:
输入:function_id = 1, z = 5
输出:[[1,4],[2,3],[3,2],[4,1]]
解释:function_id = 1 暗含的函数式子为 f(x, y) = x + y
以下 x 和 y 满足 f(x, y) 等于 5:
x=1, y=4 -> f(1, 4) = 1 + 4 = 5
x=2, y=3 -> f(2, 3) = 2 + 3 = 5
x=3, y=2 -> f(3, 2) = 3 + 2 = 5
x=4, y=1 -> f(4, 1) = 4 + 1 = 5
示例 2:
输入:function_id = 2, z = 5
输出:[[1,5],[5,1]]
解释:function_id = 2 暗含的函数式子为 f(x, y) = x * y
以下 x 和 y 满足 f(x, y) 等于 5:
x=1, y=5 -> f(1, 5) = 1 * 5 = 5
x=5, y=1 -> f(5, 1) = 5 * 1 = 5
提示:
1 <= function_id <= 9
1 <= z <= 100
题目保证 f(x, y) == z
的解处于 1 <= x, y <= 1000
的范围内。
在 1 <= x, y <= 1000
的前提下,题目保证 f(x, y)
是一个 32 位有符号整数。
""" This is the custom function interface. You should not implement it, or speculate about its implementation class CustomFunction: # Returns f(x, y) for any given positive integers x and y. # Note that f(x, y) is increasing with respect to both x and y. # i.e. f(x, y) < f(x + 1, y), f(x, y) < f(x, y + 1) def f(self, x, y): """ class Solution(object): def findSolution(self, customfunction, z): """ :type num: int :type z: int :rtype: List[List[int]] """
不过为什么看到这个题的时候,我完全没有思路呢???...
比如说我们的输入z = 6, customfunction是某个未知的运算...
假如说我们先运行customfunction.f(1,1).它在大部分情况等于1,但也有不等于的情况
如果f(1,1)大于z,那么直接返回一个空列表(因为运算函数是递增函数,所以这个时候不可能有solution)
如果f(1,1)小于z???
那么我们分别尝试下f(1,2)和f(2,1)
假如结果是f(1,2)大于z,f(2,1)小于z?
根据结果,我们可以知道f(2,2)大于max(f(1,2),f(2,1)),因此f(2,2)可以不需要尝试了,我们只需要再次尝试f(3,1)就可以了....
如果f(1,2)和f(2,1)都小于z呢?
那么此时,我们显然需要(1,3),(2,2)和(3,1)都试一试!
我们不妨画图表示一下这两种情况:
如果是第一种情况:
4 x x x x 3 x x x x 2 > x x x 1 < < ! ? 1 2 3 4
如果是第二种情况
4 ? ? ? ? 3 ! ? ? ? 2 < ! ? ? 1 < < ! ? 1 2 3 4
其中"!"代表接下来要计算的f(x,y),而?表示不知道需不需要计算,大于、小于和等于用">","<"和"="表示,"x"表示不需要计算的值。
显然,一个">"或者一个"="会让处于它右上角的部分全部变成"x",而"<"出现的时候,它右边和它上边的值都需要在下一次再次计算(如果没有受到其他">"或者"="的影响。
那么我们的第一个版本的算法也就出现了:——可能比较像动态规划
""" This is the custom function interface. You should not implement it, or speculate about its implementation class CustomFunction: # Returns f(x, y) for any given positive integers x and y. # Note that f(x, y) is increasing with respect to both x and y. # i.e. f(x, y) < f(x + 1, y), f(x, y) < f(x, y + 1) def f(self, x, y): """ class Solution(object): def findSolution(self, customfunction, z): """ :type num: int :type z: int :rtype: List[List[int]] """ result = [] #初始化一个1000*1000的矩阵(列表),其值全部为"?" #计算f(1,1),如果f(1,1)>z,那么直接返回一个空列表 #如果f(1,1)=z,直接返回[[1,1]] #如果f(1,1)<z,将f(1,2)和f(2,1)置为"!"(如果它们不是"x"的话) #计算所有的矩阵中"!"出现的f(x,y) #把结果和z进行比较,并将"!"赋值为">","<"或者"=" #如果结果是">",那么将它右边、上边和右上的矩阵值全部置为"x" #如果结果是"=",把这组解放在结果上,并将它右边、上边和右上的矩阵值全部置为"x" #如果结果是"<",那么将它右边相邻的元素和上边相邻非"x"的元素置为"!" #重复上述过程,直到矩阵中没有"?"为止,返回result.
懒得写具体的实现了,所以让ChatGPT生成了一下:
以下是根据你的描述完成的第一个版本的算法。这个算法使用了一个二维矩阵,代表所有可能的 f(x, y)
的计算状态。在计算过程中,通过不断地更新矩阵的值,得到符合条件的解。
class Solution(object): def findSolution(self, customfunction, z): """ :type customfunction: CustomFunction :type z: int :rtype: List[List[int]] """ result = [] matrix = [['?' for _ in range(1001)] for _ in range(1001)] # 计算 f(1, 1) f_1_1 = customfunction.f(1, 1) if f_1_1 > z: return result elif f_1_1 == z: result.append([1, 1]) return result else: matrix[1][1] = '!' matrix[1][2] = matrix[2][1] = '!' # 计算所有可能的 f(x, y) for x in range(1, 1001): for y in range(1, 1001): if matrix[x][y] == '!': f_x_y = customfunction.f(x, y) if f_x_y == z: result.append([x, y]) matrix[x][y] = '=' matrix[x+1:][y+1:] = 'x' elif f_x_y > z: matrix[x][y] = '>' matrix[x+1:][y+1:] = 'x' else: matrix[x][y] = '<' matrix[x+1][y] = matrix[x][y+1] = '!' return result
这个算法对 f(x, y)
进行了一些预处理,然后通过矩阵的更新,找到所有可能的解。尽管这个算法可能不是最优解,但它是一种直观的解法,可以帮助你更好地理解问题。
这个版本的算法显然是可以通过测试的,不过耗时和空间都很大。
2490ms(12.50%)和20.28MB(12.50%)
Current: 48pp(New!)
Overall: 176pp(+41pp)
那么,还有没有其他的方法可以解决这个问题呢
...我之前说过这个题似乎比较像动态规划...但是我们要如何利用这个特性呢?
...
对于这个问题,我们可以考虑使用二分搜索来加速查找。首先,我们观察到 f(x, y)
是递增函数,因此对于给定的 x
,y
,f(x, y)
的值是唯一确定的。
我们可以按照以下步骤进行优化:
- 固定一个变量,比如
x
,然后在范围[1, 1000]
内使用二分搜索查找y
,使得f(x, y) == z
。 - 如果找到了满足条件的
y
,将[x, y]
添加到结果中。 - 增加
x
并重复步骤 1。
这样,我们可以通过二分搜索在 y
的范围内快速找到符合条件的解,从而减小时间复杂度。以下是实现这一优化的代码:
class Solution(object): def findSolution(self, customfunction, z): """ :type customfunction: CustomFunction :type z: int :rtype: List[List[int]] """ result = [] for x in range(1, 1001): left, right = 1, 1000 while left <= right: mid = (left + right) // 2 value = customfunction.f(x, mid) if value == z: result.append([x, mid]) break elif value < z: left = mid + 1 else: right = mid - 1 return result
这是Python所写的代码,时间复杂度从O(n^2)
减到了O(nlogn)
,这里ChatGPT利用了对于特定的x来说,使f(x,y)=z的y是唯一的,利用这个特点简化了时间复杂度。
那么,我们能否把这两个特性结合在一起呢?
class Solution(object): def findSolution(self, customfunction, z): """ :type customfunction: CustomFunction :type z: int :rtype: List[List[int]] """ result = [] x,y,limit_x,limit_y = 1,1,1001,1001 #数据初始化 while x < limit_x or y < limit_y: left, right = 1, limit_y if limit_y == 1: break while left <= right: mid = (left + right) // 2 value = customfunction.f(x, mid) if value == z: result.append([x, mid]) y = limit_y break elif value < z: left = mid + 1 else: y = limit_y right = mid - 1 x += 1 return result
那么这段算法的性能是124ms(25.00%)和13.13MB(12.50%),和之前相比有了显著的提升!
Current: 56pp(+13pp)
Overall: 184pp(+8pp)
不过我为什么感觉还可以优化...我为什么会想到y = limit_y呢?...
后来发现这并不是把它们结合在一起的方法...而是...
class Solution(object): def findSolution(self, customfunction, z): """ :type customfunction: CustomFunction :type z: int :rtype: List[List[int]] """ result = [] x,y,limit_x,limit_y = 1,1,1001,1001 #数据初始化 while x < limit_x or y < limit_y: left, right = 1, limit_y if limit_y == 1: break while left <= right: mid = (left + right) // 2 value = customfunction.f(x, mid) if value == z: result.append([x, mid]) y = limit_y #用于快速跳出内层循环 limit_y = mid #这样子才对嘛!~ 动态更新limit_y~(利用x遍历递增的性质,之后的寻找只需要在1,limit_y)范围内执行,并采用二分查找提升效率~ break elif value < z: left = mid + 1 else: y = limit_y limit_y = mid right = mid - 1 x += 1 return result
这段代码取得了显著的时间和空间开销的下降!~
16ms(100.00%)和11.59MB(100.00%)
Current: 79pp(+23pp)
Overall: 207pp(+23pp)
Luogu P1013. 进制位
Star Rating: 3.73
题目描述
著名科学家卢斯为了检查学生对进位制的理解,他给出了如下的一张加法表,表中的字母代表数字。 例如:
其含义为:
根据这些规则可推导出:
同时可以确定该表表示的是
输入格式
第一行一个整数
以下
若记
保证至多有一组解。
输出格式
第一行输出各个字母表示什么数,格式如:L=0 K=1
第二行输出加法运算是几进制的。
若不可能组成加法表,则应输出 ERROR!
。
样例 #1
样例输入 #1
5 + L K V E L L K V E K K V E KL V V E KL KK E E KL KK KV
样例输出 #1
L=0 K=1 V=2 E=3 4
首先,我们在拿到这个题以后,一定要考虑一下先把数据输入进去
n = int(input()) table = [] for i in range(n): line = list(map(str, input().split())) teble.append(line)
然后...看不懂了...
假如说表格是这样的:
+ 0 1 0 0 1 1 1 10
这就是一个简单的二进制加法表
与此同时我们也可以改变0 和 1的顺序:
+ 0 1 1 1 10 0 0 1
这也是一个二进制表格
根据题意可知,
如果是三进制表格,那么他会是什么样的呢?
+ 2 1 0 0 2 1 0 1 10 2 1 2 11 10 2
或者说,如果0,1,2不是递增或者递减顺序?
+ 2 0 1 1 10 1 2 0 2 0 1 2 11 2 10
显然,我们已经找到破局的方法了!
我们需要先找到"0"是多少!---因为0一定在和第一行数字相等的一行,以及和第一列数字相等的一列当中,这一行和这一列相交的地方对应的字母就是"0"!
如果找到了"0",接下来要如何去做呢?
无论是几进制,两个一位数相加的结果不可能超过这个进制数字的"10+10".因此,我们可以去找结尾为"0"对应字母的值,然后断定其前边的数字是"1"!(这也就说明,这个表格右下角的子表中的值如果是两位数,不可能超过10+10!)
如果能确定出"1"是多少,那么如何确定其他的值呢?(如果有的话)
找到"1"以后,我们去找"1"对应的行和"1"对应的列,找到"2"对应的字母值,然后就简单了!固定"1"对应的行,找到"2"对应的列的字母,就能找到"3",....直到"n"对应的列为"10"为止结束循环。
(实际上,我们也可以看出来,如果输入的表格长度是n,那它应该是一个n-1进制运算表!)
思路渐渐清晰,我们也来写一下对应的代码!
s = int(input()) table = [] for i in range(s): line = list(map(str, input().split())) table.append(line) dict = {} #存储最后的映射结果 #在table中寻找table[1:][k]与table[1:][0]相等的k和table[l][1:]与table[0][1:]相等的[l],那么table[k][l]对应的字母的映射值为0. #遍历寻找结尾字符为table[k][l]的长度为2的第一个字符串table[m][n],确定table[m][n][0]对应字母的映射值为1. #如果进制数为2,即n=3,则返回结果 #否则,找到table[m][n][0]在table[0][1:]对应的位置p和table[m][n][0]在table[1:][0]对应的位置q,找到table[p][q]对应的位置字母的映射值为2 #如果进制数为3,即n=4,则返回结果 #否则,遍历table[1:][p],然后在table[1:][0]中找到table[p][q]对应的位置,确定这个映射值为3,并记录这个值作为下一次在table[1:][0]中寻找的索引,如果还没有确定所有字母,重复上述操作,直到字典长度达到s - 1. #按照格式输出结果
让ChatGPT生成了一下代码:
n = int(input()) table = [] for i in range(n): line = list(map(str, input().split())) table.append(line) def find_mapping(table, char, n, known_mapping): for i in range(1, n): if table[i][0] == char: return i, 0 if table[0][i] == char: return 0, i for i in range(1, n): for j in range(1, n): if table[i][j] == char: if table[i][0] in known_mapping: return i, 0 else: return 0, j def solve(table): n = len(table) known_mapping = {} # 存储映射结果 # 寻找0的映射 for i in range(1, n): for j in range(1, n): if len(table[i][j]) == 2: char = table[i][j][1] known_mapping[char] = 0 break # 寻找1到n-1的映射 for value in range(1, n): for i in range(1, n): for j in range(1, n): if len(table[i][j]) == 2 and table[i][j][0] == str(value): char = table[i][j][1] if char not in known_mapping: row, col = find_mapping(table, char, n, known_mapping) known_mapping[char] = value return known_mapping def print_result(known_mapping): result_str = ' '.join([f'{char}={value}' for char, value in sorted(known_mapping.items())]) print(result_str) def main(): known_mapping = solve(table) if len(known_mapping) != n - 1: print('ERROR!') else: print_result(known_mapping) if __name__ == "__main__": main()
看看能否通过测试吧!
第一次测试发现有三个WE...可能是需要按照表格第一行的顺序输出映射值,字典的顺序可能和表格第一行/第一列顺序不一样...
(因为本题有一个前置条件,行和列出现的顺序是相同的)
..诶?
也许我们可以简化一下代码!
s = int(input()) table = [] for i in range(s): line = list(map(str, input().split())) table.append(line) dict = {} #存储最后的映射结果 #在table中寻找table[1:][k]与table[1:][0]相等的k,那么table[k][k]对应的字母的映射值为0. #遍历寻找结尾字符为table[k][k]的长度为2的第一个字符串table[m][n],确定table[m][n][0]对应字母的映射值为1. #如果进制数为2,即n=3,则返回结果 #否则,找到table[m][n][0]在table[0][1:]对应的位置p,找到table[p][p]对应的位置字母的映射值为2 #如果进制数为3,即n=4,则返回结果 #否则,遍历table[1:][p],然后在table[1:][0]中找到table[p][q]对应的位置,确定这个映射值为3,并记录这个值作为下一次在table[1:][0]中寻找的索引,如果还没有确定所有字母,重复上述操作,直到字典长度达到s - 1. #按照表格中第一行的字母顺序输出结果,并输出进制数
对应的代码如下:
s = int(input()) table = [] for i in range(s): line = list(map(str, input().split())) table.append(line) #print(table) def solve(table): n = len(table) known_mapping = {} # 存储映射结果 # 寻找0的映射 for i in range(1, n): #print(f"i={i}") if table[i][1:] == table[0][1:]: char = table[i][i][0] known_mapping[char] = 0 break # 寻找1的映射 for i in range(1,n): for j in range(1,n): if len(table[i][j]) == 2: known_mapping[table[i][j][0]] = 1 break if len(known_mapping) == 2: break if n == 3: return known_mapping # 寻找2的映射,初始化一个next_str next_str = table[i][j][0] for i in range(1,n): if table[0][i] == next_str: known_mapping[table[i][i]] = 2 idx_1 = i break if n == 4: return known_mapping next_str = table[idx_1][idx_1] #寻找3到n-2的映射,range的范围是(3,n-1) for value in range(3, n-1): for i in range(1, n): # 在第1行找到"2",..."n-1"对应的索引 if table[0][i] == next_str: known_mapping[table[idx_1][i]] = value next_str = table[idx_1][i] break return known_mapping def print_result(known_mapping): for i in range(1,s): print(f"{table[0][i]}={known_mapping[table[0][i]]}",end=" ") print() print(s - 1) def main(): known_mapping = solve(table) #print(known_mapping) if len(known_mapping) != s - 1: print('ERROR!') else: print_result(known_mapping) if __name__ == "__main__": main()
这段代码拿到了80分的分数,不过为什么会有一个过不去的测试用例呢...?
Current: 48pp(New!)
Overall: 246pp(+39pp)
读取的是M,期望E
可能是对某个异常情况没有正确处理吧...
为了进一步验证算法正确性,我们需要对Table全部检查一遍,如果输出有错误,那么也会返回error!
s = int(input()) table = [] for i in range(s): line = list(map(str, input().split())) table.append(line) #print(table) def solve(table): n = len(table) known_mapping = {} # 存储映射结果 # 寻找0的映射 for i in range(1, n): #print(f"i={i}") if table[i][1:] == table[0][1:]: char = table[i][i][0] known_mapping[char] = 0 break # 寻找1的映射 for i in range(1,n): for j in range(1,n): if len(table[i][j]) == 2: known_mapping[table[i][j][0]] = 1 break if len(known_mapping) == 2: break if n == 3: return known_mapping # 寻找2的映射,初始化一个next_str next_str = table[i][j][0] for i in range(1,n): if table[0][i] == next_str: known_mapping[table[i][i]] = 2 idx_1 = i break if n == 4: return known_mapping next_str = table[idx_1][idx_1] #寻找3到n-2的映射,range的范围是(3,n-1) for value in range(3, n-1): for i in range(1, n): # 在第1行找到"2",..."n-1"对应的索引 if table[0][i] == next_str: known_mapping[table[idx_1][i]] = value next_str = table[idx_1][i] break return known_mapping def print_result(known_mapping): for i in range(1,s): print(f"{table[0][i]}={known_mapping[table[0][i]]}",end=" ") print() print(s - 1) def cv_int(string,known_mapping): if len(string) == 1: return known_mapping[string] else: return known_mapping[string[0]] * (s-1) + known_mapping[string[1]] def main(): known_mapping = solve(table) #print(known_mapping) if len(known_mapping) != s - 1: print('ERROR!') else: #检查原来的表格,验证每个值是否成立 int_table = [] for i in range(0,s): int_table_line = [] for j in range(0,s): if i == 0 and j == 0: int_table_line.append(0) else: int_table_line.append(cv_int(table[i][j],known_mapping)) int_table.append(int_table_line) #print(int_table) valid = True for i in range(1,s): for j in range(1,s): valid = valid and int_table[i][0] + int_table[0][j] == int_table[i][j] if valid: print_result(known_mapping) else: print('ERROR!') if __name__ == "__main__": main()
那么我们也终于通过了这个题目~!
Current:70pp(+22pp)
Overall:267pp(+21pp)
洛谷P1008 三连击
Star Rating:2.64
题目背景
本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序。
题目描述
将
输入格式
无
输出格式
若干行,每行
样例 #1
样例输入 #1
无
样例输出 #1
192 384 576 * * * ... * * * (剩余部分不予展示)
总感觉这道题...应该只是考查我们的理解能力吧..
我大概知道是什么意思了...
感觉有一种很快的方法就是把答案直接列出来,然后print > <
不过...我们要如何才能知道所有的答案呢?
三个数是1:2:3,因此第一个数必须是一个小于333的数字;
要同时出现1~9这9个数字,因此第一个数中必须出现三个不同的数字,而且不能出现0
这样就确定了第一个数一定在123~329之间
基于此方法,我们设计了一个初版的基于穷举的程序把它们都找出来
first_int = 123 while first_int <= 329: dict = {} for char in str(first_int): dict[char] = 1 for char in str(first_int * 2): dict[char] = 1 for char in str(first_int * 3): dict[char] = 1 if len(dict) == 9: print(first_int, first_int * 2, first_int * 3) first_int += 1
看起来程序输出了正确结果~
192 384 576 219 438 657 267 534 801 273 546 819 327 654 981
一共有5组解!
提交一下试试~不过...发现一个不对的解...因为中间这组把0也映射进去了!
微调了一下!
first_int = 123 while first_int <= 329: dict = {} for char in str(first_int): dict[char] = 1 for char in str(first_int * 2): dict[char] = 1 for char in str(first_int * 3): dict[char] = 1 if len(dict) == 9 and '0' not in dict: #如果0不在字典中 print(first_int, first_int * 2, first_int * 3) first_int += 1
这样的话就只有4组解了!
192 384 576 219 438 657 273 546 819 327 654 981
Yes, Accepted啦~
Current: 24pp(New!)
Overall: 284pp(+14pp)
本文作者:Yuzu_OvO(喵露露版)
本文链接:https://www.cnblogs.com/yuzusbase/p/17971581
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步