LeetCode209长度最小的子数组
一、题目:. - 力扣(LeetCode)
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的
子数组
[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
二、自己写(不会自己写)
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
i = 0
j = 0
sum = 0
subl = len(nums)+1
for j in range(len(nums)):
sum += nums[j]
while sum >= target:
# subl = j-i+1
subl = min(subl, j-i+1)
sum = sum-nums[i]
i += 1
return subl if subl <= len(nums) else 0
-
为什么要更新subl,直接用subl = j - i + 1,放在循环while中为什么不可以
-
直接在
while
循环中使用subl = j - i + 1
,而不进行比较和更新是不行的,因为这将始终记录当前的子数组长度,而不会确保它是最小的子数组长度。 -
return subl的位置放在哪里?
-
第一次写没有初始化subl,直接return subl出错,因为变量
subl
在被正确初始化之前就被使用了。在代码中,subl
是用来存储最小子数组的长度,该子数组的元素和至少等于目标值。然而,subl
只在while
循环中定义,如果条件sum >= target
从未满足,那么这个循环就不会执行。如果while
循环从未运行(例如,没有任何子数组满足条件sum >= target
),那么当尝试返回subl
时,subl
将保持未定义状态,从而导致UnboundLocalError
。 -
subl初始化应该多少?
-
如果初始化为len(nums)会导致如果nums元素全部相加还是小于target时 return subl if subl <= len(nums) else 0会返回subl初始化值,错误,所以subl等于len(nums)+1可以判断subl是不是更新了
三、滑动窗口:
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
LeetCode59螺旋矩阵
一、题目:. - 力扣(LeetCode)
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
二、自己写:
def generateMatrix(self, n: int) -> List[List[int]]:
startx = 0
starty = 0
offset = 1
count = 1
num = 0
nums = [0][0]*(n**2)
while num < n/2:
num += 1
for j in range(starty, n-offset):
nums[startx][j] = count
count += 1
for i in range(startx, n-offset):
nums[i][j] = count
count += 1
for j in range(starty, n-offset, -1):
nums[n-offset][j] = count
count += 1
for i in range(starty, n-offset, -1):
nums[i][starty] = count
count += 1
offset += 1
startx += 1
starty += 1
if n%2 == 1:
nums[n/2][n/2] = n**2
问题1:
nums
的初始化方式不正确。写的 nums = [0][0] * (n**2)
实际上是在创建一个整数列表,而不是一个二维列表。具体来说,[0][0]
是取列表 [0]
的第一个元素,即 0
,因此 nums
变成了一个整数而不是一个列表。
问题2:
n/2
的结果是一个浮点数,即使 n
是整数。例如,当 n = 5
时,n/2
的结果是 2.5
,而列表索引必须是整数。
问题3:
螺旋矩阵的构建逻辑存在一些问题。具体来说:
- 在构建矩阵的过程中,第二个和第四个
for
循环中的索引更新不正确,导致矩阵未按照预期填充。 - 在第三个和第四个
for
循环中,你的循环方向(递减)与初始化的索引不一致,这导致填充不正确。 for j in range(n-offset, starty, -1):这个步长为-1时边界前一个要大于后一个 - 当
n
是奇数时,中心元素填充逻辑正确,但整体矩阵构建逻辑仍需调整。
修改后:
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
startx = 0
starty = 0
offset = 1
count = 1
num = 0
nums = [[0] * n for _ in range(n)] # 初始化 n x n 的二维列表
while num < n/2:
num += 1
for j in range(starty, n-offset):
nums[startx][j] = count
count += 1
for i in range(startx, n-offset):
nums[i][n-offset] = count
count += 1
for j in range(n-offset, starty, -1):
nums[n-offset][j] = count
count += 1
for i in range(n-offset, startx, -1):
nums[i][starty] = count
count += 1
offset += 1
startx += 1
starty += 1
if n%2 == 1:
nums[n//2][n//2] = n**2
return nums
三、循环不变量
求解本题依然是要坚持循环不变量原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
由外向内一圈一圈这么画下去。
58 区间数和
一、题目58. 区间和 | 代码随想录
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间下标:a,b (b > = a),直至文件结束。
输出描述
输出每个指定区间内元素的总和。
二、自己写
写了一下午,一直不对(我好菜啊)
if __name__ == "__main__":
try:
num = int(input())
num_value = [0] * num
sum_value = 0
# print("输入数组元素:")
for i in range(num):
value = int(input())
sum_value += value
num_value[i] = sum_value
# num_value[i] += value # 这样不行,num_value[i]每次加都是加的自己
# num_value = [0] + num_value
# print("输入区间来计算总和 (格式: start end,输入'quit'退出):")
while True:
try:
line = input()
if line.lower() == 'quit':
break
a, b = map(int, line.split())
if a == 0:
print(num_value[b])
else:
print(num_value[b]- num_value[a-1])
except ValueError:
pass # 这里可以处理ValueError异常
except EOFError:
pass # 这里处理EOFError异常,防止程序因输入结束而崩溃
好多问题:
1,数组的输入:应该使用 range(num)
来遍历输入的数组元素,而不是 for i in num
,因为 num
是整数,不能直接用于循环。
2,区间计算:
input()
接收输入,map(int, line.split())
将输入拆分为两个整数a
和b
。- 使用
sum(nums[a:b+1])
计算从a
到b
索引范围内的元素总和。 split()
将字符串按分隔符拆分成列表,默认使用空白字符作为分隔符。map(int, ...)
可以将列表中的字符串元素转换为整数。
3,错误处理:
try-except
块处理可能的输入错误,例如用户没有输入两个整数或者输入的内容不符合要求。-
line.lower()
:这个方法将字符串line
中的所有字母转换为小写字母。例如,如果用户输入"Quit"
、"QUIT"
或"quit"
,line.lower()
都会将其转换为"quit"
。 -
错误
EOFError: EOF when reading a line
通常是因为在读取输入时,输入流已经结束(通常在输入文件结束或标准输入被关闭的情况下发生)捕获EOFError
:在主函数的外层try-except
中捕获EOFError
,以处理当输入流结束时的情况。 -
不print的时候可以用pass
三、前缀和
前缀和 在涉及计算区间和的问题时非常有用!
前缀和的思路其实很简单
例如,我们要统计 vec[i] 这个数组上的区间和。
我们先做累加,即 p[i] 表示 下标 0 到 i 的 vec[i] 累加 之和。
如果,我们想统计,在vec数组上 下标 2 到下标 5 之间的累加和,那是不是就用 p[5] - p[1] 就可以了。
为什么呢?
p[1] = vec[0] + vec[1];
p[5] = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];
p[5] - p[1] = vec[2] + vec[3] + vec[4] + vec[5];
import sys
input = sys.stdin.read
def main():
data = input().split()
index = 0
n = int(data[index])
index += 1
vec = []
for i in range(n):
vec.append(int(data[index + i]))
index += n
p = [0] * n
presum = 0
for i in range(n):
presum += vec[i]
p[i] = presum
results = []
while index < len(data):
a = int(data[index])
b = int(data[index + 1])
index += 2
if a == 0:
sum_value = p[b]
else:
sum_value = p[b] - p[a - 1]
results.append(sum_value)
for result in results:
print(result)
if __name__ == "__main__":
main()
44
开发商购买土地
一,题目:44. 开发商购买土地(第五期模拟笔试)
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。
然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。
为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。
注意:区块不可再分。
二,自己写
刚开始没有搞清楚题目意思,题目意思是将m*n的数组按照行或者列分为两部分,然后两部分的元素分别相加,得到A和B,然后求A和B差值的最小值。
思路:先把输入数据存成一个二维列表,然后计算出每一行每一列的和分别存到n维和m维列表中然后按行和列比较怎么划分差值最小
def find_min_difference(n, m, grid):
# 计算每一行的总和,存储在n_sum中
n_sum = [sum(row) for row in grid]
# 计算每一列的总和,存储在m_sum中
m_sum = [sum(grid[i][j] for i in range(n)) for j in range(m)]
# 计算整个矩阵的总和
total_sum = sum(n_sum)
min_diff = float('inf')
# 横向划分
for i in range(1, n):
top_sum = sum(n_sum[:i])
bottom_sum = total_sum - top_sum
diff = abs(top_sum - bottom_sum)
min_diff = min(min_diff, diff)
# 纵向划分
for j in range(1, m):
left_sum = sum(m_sum[:j])
right_sum = total_sum - left_sum
diff = abs(left_sum - right_sum)
min_diff = min(min_diff, diff)
return min_diff
if __name__ == "__main__":
# 输入数据并存储为二维列表
n, m = map(int, input().split())
grid = []
for _ in range(n):
grid.append(list(map(int, input().split())))
# 计算并输出最小差值
result = find_min_difference(n, m, grid)
print(result)
三、优化写法
首先定义一个列表,然后
-
计算总价值:
- 使用
total_sum = sum(sum(row) for row in grid)
计算整个区域所有区块的总价值。
- 使用
-
横向划分:
- 使用
for i in range(1, n)
遍历所有可能的横向划分方式。 - 通过计算上部分和下部分的总和,得到两个区域的总价值之差。
- 使用
-
纵向划分:
- 使用
for j in range(1, m)
遍历所有可能的纵向划分方式。 - 通过计算左部分和右部分的总和,得到两个区域的总价值之差。
- 使用
-
最小差值:
- 记录所有划分方式中最小的差值并返回。
def min_land_value_difference(n, m, grid):
# 计算整个区域的总价值
total_sum = sum(sum(row) for row in grid)
min_diff = float('inf')
# 横向划分
for i in range(1, n):
sum_top = sum(sum(grid[x]) for x in range(i))
sum_bottom = total_sum - sum_top
min_diff = min(min_diff, abs(sum_top - sum_bottom))
# 纵向划分
for j in range(1, m):
sum_left = sum(grid[x][y] for x in range(n) for y in range(j))
sum_right = total_sum - sum_left
min_diff = min(min_diff, abs(sum_left - sum_right))
return min_diff
if __name__ == "__main__":
try:
try:
line = input()
n, m = map(int, line.split())
grid = []
for _ in range(n):
grid.append(list(map(int, input().split())))
result = min_land_value_difference(n, m, grid)
print(result)
except ValueError:
pass # 这里可以处理ValueError异常
except EOFError:
pass # 这里处理EOFError异常,防止程序因输入结束而崩溃