Python补题——0连连看

0连连看 - 蓝桥云课

方法思路

对角线定义:右对角线由i+j标识,左对角线由j-i标识。

统计方法:遍历矩阵中的每个元素,使用两个字典分别统计右对角线和左对角线上的元素出现次数。

累加对数:对于每个元素,累加当前对角线中已存在的相同值的数量,然后更新计数器。

解决代码:

from collections import defaultdict,Counter
n,m = map(int , input().split())
g = [ list(map(int,input().split())) for _ in range(n)]
ans = 0
left = defaultdict(Counter)
right = defaultdict(Counter)

for i in range(n) :
    for j in range(m):
        x = g[i][j]
        ans += left[j-i][x]+right[i+j][x]
        left[j-i][x]+=1
        right[i+j][x]+=1
print(ans*2)

我们发现有新朋友defaultdict,Counter,先来看看left和right变成了什么

from collections import defaultdict,Counter
n,m = map(int , input().split())
g = [ list(map(int,input().split())) for _ in range(n)]
ans = 0
left = defaultdict(Counter)
right = defaultdict(Counter)

for i in range(n) :
    for j in range(m):
        x = g[i][j]
        ans += left[j-i][x]+right[i+j][x]
        left[j-i][x]+=1
        right[i+j][x]+=1
print(ans*2)
print('left:',left)
print('right:',right)
# 测试用例:
# 3 2
# 1 2
# 2 3
# 3 2
# 6
# left: defaultdict(<class 'collections.Counter'>, {0: Counter({1: 1, 3: 1}), 1: Counter({2: 1}), -1: Counter({2: 2}), -2: Counter({3: 1})})
# right: defaultdict(<class 'collections.Counter'>, {0: Counter({1: 1}), 1: Counter({2: 2}), 2: Counter({3: 2}), 3: Counter({2: 1})})

原理与作用详解:defaultdict(Counter) 的本质

1. 先理解普通字典的局限性

普通字典(dict)在访问不存在的键时会直接报错 KeyError

2. defaultdict 的作用

defaultdictcollections 模块中的一个字典变种。它的核心功能是:

自动为不存在的键生成默认值

默认值的类型由你指定(例如 intlistCounter 等)。

from collections import defaultdict

d = defaultdict(int)  # 指定默认值为整数0
d["apple"] += 1        # 自动创建键"apple",初始值0,然后+1 → 最终d["apple"] = 1
3. Counter 的作用

Countercollections 模块中的另一个工具,专门用于快速统计元素出现次数。

from collections import Counter

lst = ["apple", "banana", "apple", "orange"]
counter = Counter(lst)
print(counter)  # 输出:{"apple":2, "banana":1, "orange":1}
4. defaultdict(Counter) 的联合使用

当我们将 defaultdict 的默认值类型指定为 Counter 时,效果如下:

每个键(例如对角线标识 i+j)对应的值是一个独立的 Counter

每个 Counter 可以自动统计该键下的子键(例如矩阵中的数值 x)的出现次数。

from collections import defaultdict, Counter

# 创建一个字典,每个键的默认值是一个空的Counter
dd = defaultdict(Counter)

# 操作示例
dd["diag1"]["apple"] += 1  # 自动创建键"diag1",值是一个Counter,统计"apple"出现1次
dd["diag1"]["apple"] += 1  # 值变为{"apple":2}
dd["diag2"]["banana"] = 5  # 自动创建键"diag2",值是一个Counter,统计"banana"出现5次
5. 在题目中的具体应用

题目中需要统计每个对角线上的数值出现次数:

右对角线:用 i+j 作为键,对应一个 Counter,记录该对角线上每个数值的出现次数。

左对角线:用 j-i 作为键,对应另一个 Counter

for i in range(n):
    for j in range(m):
        x = g[i][j]
        # 查询当前对角线是否已有x的计数
        ans += right[i+j][x]  # 右对角线上之前x出现的次数
        ans += left[j-i][x]   # 左对角线上之前x出现的次数
        # 更新计数器
        right[i+j][x] += 1
        left[j-i][x] += 1
6. 为什么不用 defaultdict(int)

假设用 defaultdict(int)

right = defaultdict(int)
# 当处理右对角线时:
key = i + j
ans += right[(key, x)]  # 需要将对角线和x组合成一个复合键
right[(key, x)] += 1

缺点:需要手动拼接复合键 (i+j, x),代码不够直观。

defaultdict(Counter) 的优势:天然支持两层结构,直接通过 right[i+j][x] 访问,代码更清晰。

7. 总结:defaultdict(Counter) 的定位

外层结构:一个字典,键是某种分类标识(如对角线)。

内层结构:每个分类标识下,自动维护一个计数器,统计子类元素(如数值)的出现次数。

本质:一种双层嵌套的计数结构,适合需要按类别统计子元素出现次数的场景。

8. 类比生活场景

想象一个超市的货架管理:

外层字典:键是货架编号(如"A1", "B2")。

内层Counter:每个货架上的商品(如"苹果"、"香蕉")的库存数量。

defaultdict(Counter):自动为每个新货架生成一个空的库存表(Counter),无需手动初始化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值