代码随想录跟练第二天——LeetCode209长度最小的子数组、59螺旋矩阵、58区间和

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:

螺旋矩阵的构建逻辑存在一些问题。具体来说:

  1. 在构建矩阵的过程中,第二个和第四个 for 循环中的索引更新不正确,导致矩阵未按照预期填充。
  2. 在第三个和第四个 for 循环中,你的循环方向(递减)与初始化的索引不一致,这导致填充不正确。 for j in range(n-offset, starty, -1):这个步长为-1时边界前一个要大于后一个
  3. 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()) 将输入拆分为两个整数 ab
  • 使用 sum(nums[a:b+1]) 计算从 ab 索引范围内的元素总和。
  • 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异常,防止程序因输入结束而崩溃

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值