今天在像以前一样 做题的时候,遇到一个迷一样的 BUG ,仔细一想才想起来这是Python的一个特性,以前也遇到过,没想到今天又遇到了。话不多说,先来看题:
学习Python中有不明白推荐加入交流群
号:516107834
群里有志同道合的小伙伴,互帮互助,
群里有不错的学习教程!
题目要求
问题描述
在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩形指将横坐标范围从x1到x2,纵坐标范围从y1到y2之间的区域涂上颜色。
下图给出了一个画了两个矩形的例子。第一个矩形是(1,1) 到(4, 4),用绿色和紫色表示。第二个矩形是(2, 3)到(6, 5),用蓝色和紫色表示。图中,一共有15个单位的面积被涂上颜色,其中紫色部分被涂了两次,但在计算面积时只计算一次。在实际的涂色过程中,所有的矩形都涂成统一的颜色,图中显示不同颜色仅为说明方便。
给出所有要画的矩形,请问总共有多少个单位的面积被涂上颜色。
输入格式
输入的第一行包含一个整数n,表示要画的矩形的个数。
接下来n行,每行4个非负整数,分别表示要画的矩形的左下角的横坐标与纵坐标,以及右上角的横坐标与纵坐标。
输出格式
输出一个整数,表示有多少个单位的面积被涂上颜色。
样例输入
2
1 1 4 4
2 3 6 5
样例输出
15
评测用例规模与约定
1<=n<=100,0<=横坐标、纵坐标<=100。
当时我的答案是这样的:
n = int(input())
# 生成一个坐标系块,默认全为 0
panel = [[0]*100]*100
# 色块数量
cnt = 0
for i in range(n):
read = [int(x) for x in input().split()]
for x in range(read[0], read[2]):
for y in range(read[1], read[3]):
if panel[x][y] == 0:
panel[x][y] = 1
cnt += 1
print(cnt)
却发现结果不太对,输入示例数据,结果只有 4 ?剩下的 11 个是被吃了吗?仔细看逻辑也没问题啊,这时候突然想到 Python 的一个特性,赶紧写个测试代码试一下:
a = [[0]*3]*3
print(a)
a[0][0] = 1
print(a)
结果如下:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
我们发现,明明只是置 [0][0] 为 1 ,怎么所有的第二维数组的 [0] 全为 1 了呢?你遇到过这种情况吗?
原来这是因为 Python 相同的值只存一份的特性决定的。不管有多少个 [0,0,0] 对于 Python 来说,内存中只存一份,所有的 [0,0,0] 都是这块内存的引用,所以在对二维数组的 [0][0] 进行赋值的时候,内存中的值被改变,所有 [0,0,0] 的引用也被改变!正是这个原因,所有答案输出的结果才与我们预期的不一样。要想正确输出只需将代码稍微改一下即可:
n = int(input())
panel = [0]*10000
cnt = 0
for i in range(n):
read = [int(x) for x in input().split()]
for x in range(read[0], read[2]):
for y in range(read[1], read[3]):
if panel[x*100+y] == 0:
panel[x*100+y] = 1
cnt += 1
print(cnt)
其实对于 Python 来说,不光是相同的列表只存一份,元组、集合、字典也是只存一份,所以一个相同的数据赋值给多个变量时,如果进行修改操作时要小心了,一不小心就把所有的地方都改了。
另外对于 ‘a' , 1 等常量也遵循只存一份的原则。
a = 1
b = 1
对于以上代码,将 1 赋值给 a ,再将 1 赋值给 b 。在这里 a 代表的 1 和 b 代表的 1 其实是同一个 1 ,引用的是同一个地址。也就是说,在 Python 中,没有真正的值传递,所有的数据都是引用类型的。只不过指向常量等不可变类型的变量在改变时会换一个内存地址,若是列表这种可变类型,在修改时就会直接修改内存中的值,因此所有的引用都会被改变。你明白了吗?
网友评论