代码随想录算法训练营第二天 | 209.长度最小的子数组、59.螺旋矩阵II、区间和、开发商购买土地

继续每天补一个,最好能加快进度赶上正常的TAT,可惜基础不够牢,边学边做
滑动窗口和双指针的条件,包括滑动窗口的移动要求要清楚

209.长度最小的子数组

题目描述:

给定一个含有 n 个正整数的数组和一个正整数 target
找出该数组中满足其总和大于等于 target 的长度最小的子数组[nums_l, nums_(l+1), ..., nums_(r-1), nums_r],并返回其长度。如果不存在符合条件的子数组,返回 0

思路整理:

  1. 双指针法
    利用sum计算总和,比较和target的大小,没超过target,则右指针继续移动,超过target,则左指针移动收缩
class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        left, sums = 0, 0
        minlen = float('inf')
        for right in range(len(nums)):
            sums += nums[right]
            while sums >= target:
                # 用判断条件来控制left移动
                minlen = min(minlen,right - left + 1) # 确保right指针已经指向了下个元素
                sums -= nums[left]
                left += 1
        return minlen if minlen != float('inf') else 0

2.暴力法
暴力法相当于使用两层for循环,第一层取不同的数组起点,第二层取不同的数组终点,来求解最符合要求的数组,比较麻烦。

59.螺旋矩阵II

题目:

给你一个正整数 n ,生成一个包含 1n^2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

思路整理:

  1. 双循环:我理解的核心是两个,一个是保证每次排列边的时候计算法则要保持一致,放置四条边时个数之类的保持一致,不然算法计算上会有可能产生冲突;二是第一层循环采用的是offset,通过n - offset来控制每层循环缩小,最后再判断为奇数的情况看是否需要填充最后一个数。
class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        nums = [[0] * n for _ in range(n)]
        startx, starty = 0, 0  # 定义起始点
        loop, mid = n // 2, n // 2
        count = 1

        for offset in range(1, loop + 1):
            # 从左到右(左闭右开)
            for i in range(starty, n - offset):
                nums[startx][i] = count
                count += 1
             # 从上到下(上闭下开)
            for i in range(startx, n-offset):
                nums[i][n - offset] = count
                count += 1
            # 从右到左(右闭左开),注意方向
            for i in range(n - offset, starty, -1):
                nums[n - offset][i] = count
                count += 1
            # 从下到上(下闭上开),注意方向
            for i in range(n - offset, startx, -1):
                nums[i][starty] = count
                count += 1
            startx += 1
            starty += 1
        
        if n % 2 != 0:
            nums[mid][mid] = count
        return nums
                            
  1. 定义四个边界:
    分别对上下左右四个点的位置进行定义,这样条件从正方形框逐步缩小变成了每条边的指针位置,优势是不用单独考虑中间那个位置
class Solution(object):
    def generateMatrix(self, n):
        if n <= 0:
            return []
        
        # 初始化 n x n 矩阵
        matrix = [[0]*n for _ in range(n)]

        # 初始化边界和起始值
        top, bottom, left, right = 0, n-1, 0, n-1
        num = 1

        while top <= bottom and left <= right:
            # 从左到右填充上边界
            for i in range(left, right + 1):
                matrix[top][i] = num
                num += 1
            top += 1

            # 从上到下填充右边界
            for i in range(top, bottom + 1):
                matrix[i][right] = num
                num += 1
            right -= 1

            # 从右到左填充下边界

            for i in range(right, left - 1, -1):
                matrix[bottom][i] = num
                num += 1
            bottom -= 1

            # 从下到上填充左边界

            for i in range(bottom, top - 1, -1):
                matrix[i][left] = num
                num += 1
            left += 1

        return matrix

区间和

题目:

给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。

思路整理:

通过利用p存储累计和,读取a和b时通过p(b) - p(a - 1)获得该区间和。

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
    count = 0
    for v in range(n):
        count += vec[v]
        p[v] = count

    results = []
    while index < len(data):
        a = int(data[index])  # 注意如何提取的a和b
        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()
    

开发商购买土地

题目描述:

在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。

现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。

然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。

为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。

注意:区块不可再分。

输入输出示例:

【输入描述】

· 第一行输入两个正整数,代表 n 和 m。
· 接下来的 n 行,每行输出 m 个正整数。

【输出描述】

· 请输出一个整数,代表两个子区域内土地总价值之间的最小差距。

【输入示例】

3 3
1 2 3
2 1 3
1 2 3

【输出示例】

0

【提示信息】

· 如果将区域按照如下方式划分:
1 2 | 3
2 1 | 3
1 2 | 3
两个子区域内土地总价值之间的最小差距可以达到 0。

【数据范围】:

·1 <= n, m <= 100;
·n 和 m 不同时为 1。

思路整理:

分别计算每一行和每一列的和,类似前缀和的思路来比较,如果两块土地差距最小,啧单边的土地价值应该尽可能接近总和的一半。

def main():
    import sys
    input = sys.stdin.read
    data = input().split()
    
    n,m = int(data[0]),int(data[1])
    vec = []
    index = 2
    horizontal = []
    for i in range(n):
        row = []
        sums = 0
        for j in range(m):
            num = int(data[index])
            index += 1
            sums += num
            row.append(num)
        vec.append(row)
        horizontal.append(sums)
    total_sum = sum(horizontal)
        
    vertical = [0] * m
    for j in range(m):
        for i in range(n):
            vertical[j] += vec[i][j]
            
    result = float('inf')
    horizontalCut = 0
    for i in range(n):
        horizontalCut += horizontal[i]
        result = min(result, abs(total_sum - 2*horizontalCut))
        
    verticalCut = 0
    for j in range(m):
        verticalCut += vertical[j]
        result = min(result, abs(total_sum - 2*verticalCut))
        
    print(result)
    
if __name__ == "__main__":
    main()

官方还提供了一个方案,在计算完行列结果即开始进行比较,对整个过程略微优化。

def main():
    import sys
    input = sys.stdin.read
    data = input().split()
    
    idx = 0
    n = int(data[idx])
    idx += 1
    m = int(data[idx])
    idx += 1
    sum = 0
    vec = []
    for i in range(n):
        row = []
        for j in range(m):
            num = int(data[idx])
            idx += 1
            row.append(num)
            sum += num
        vec.append(row)

    result = float('inf')
    
    count = 0
    # 行切分
    for i in range(n):
        
        for j in range(m):
            count += vec[i][j]
            # 遍历到行末尾时候开始统计
            if j == m - 1:
                result = min(result, abs(sum - 2 * count))

    count = 0
    # 列切分
    for j in range(m):
        
        for i in range(n):
            count += vec[i][j]
            # 遍历到列末尾时候开始统计
            if i == n - 1:
                result = min(result, abs(sum - 2 * count))

    print(result)

if __name__ == "__main__":
    main()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容