LeetCode LCR180文件组合

滑动窗口算法:寻找连续文件编号组合

问题描述

在文件传输过程中,待传输的文件被切分成多个部分,每个部分的文件编号为一个正整数(至少有两个文件)。传输的要求是:找到所有连续文件编号的组合,使得这些文件编号的总和等于接收方指定的数字 target。返回的结果需要满足以下规则:

  1. 每种组合按照文件编号升序排列。

  2. 不同组合按照第一个文件编号升序排列。

例如,当 target = 15 时,符合条件的组合有:

  • [1, 2, 3, 4, 5](因为 1 + 2 + 3 + 4 + 5 = 15

  • [4, 5, 6](因为 4 + 5 + 6 = 15

  • [7, 8](因为 7 + 8 = 15

解题思路

这个问题可以看作是一个典型的滑动窗口 问题。我们需要找到所有连续的文件编号组合,使得它们的总和等于 target。滑动窗口算法非常适合解决这种连续子数组或子序列的问题。

滑动窗口的核心思想

滑动窗口算法通过维护一个窗口(通常是一个连续的子数组或子序列),在满足一定条件的情况下,动态调整窗口的起始和结束位置。具体到这个问题:

  1. 初始化窗口 :使用两个指针 leftright,分别指向窗口的起始和结束位置。

  2. 计算窗口内的总和

    • 如果总和小于 target,则扩大窗口(移动 right 指针)。

    • 如果总和大于 target,则缩小窗口(移动 left 指针)。

    • 如果总和等于 target,则记录当前的组合,并继续寻找下一个可能的组合。

  3. 终止条件 :当 left 指针超过 target / 2 时,停止搜索(因为至少需要两个文件编号)。

为什么滑动窗口适合这个问题?

  • 连续子序列:文件编号是连续的,滑动窗口天然适合处理连续子序列的问题。

  • 高效性:滑动窗口的时间复杂度为 O(n),远优于暴力枚举的 O(n²)。

  • 简洁性:代码实现简单,逻辑清晰。

代码实现

cs 复制代码
#include <stdio.h>
#include <stdlib.h>

int** fileCombination(int target, int* returnSize, int** returnColumnSizes) {
    // 初始化结果数组
    int** result = (int**)malloc(1000 * sizeof(int*));
    *returnColumnSizes = (int*)malloc(1000 * sizeof(int));
    *returnSize = 0;

    int left = 1, right = 1; // 窗口的起始和结束位置
    int sum = 0; // 窗口内文件编号的总和

    while (left <= target / 2) {
        if (sum < target) {
            // 总和小于 target,扩大窗口
            sum += right;
            right++;
        } else if (sum > target) {
            // 总和大于 target,缩小窗口
            sum -= left;
            left++;
        } else {
            // 找到符合条件的组合
            int* combination = (int*)malloc((right - left) * sizeof(int));
            for (int i = left; i < right; i++) {
                combination[i - left] = i;
            }
            (*returnColumnSizes)[*returnSize] = right - left;
            result[*returnSize] = combination;
            (*returnSize)++;

            // 移动左指针,继续寻找下一个组合
            sum -= left;
            left++;
        }
    }

    return result;
}

int main() {
    int target = 15;
    int returnSize;
    int* returnColumnSizes;
    int** result = fileCombination(target, &returnSize, &returnColumnSizes);

    // 输出结果
    for (int i = 0; i < returnSize; i++) {
        for (int j = 0; j < returnColumnSizes[i]; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
        free(result[i]); // 释放每个组合的内存
    }

    // 释放结果数组和列大小数组
    free(result);
    free(returnColumnSizes);

    return 0;
}

代码解析

初始化

  • result 用于存储所有符合条件的组合。

  • returnColumnSizes 用于存储每个组合的大小。

  • returnSize 用于记录符合条件的组合数量。

滑动窗口逻辑

  • 使用 leftright 指针维护窗口的起始和结束位置。

  • 通过调整 leftright 指针,动态计算窗口内的总和。

记录结果

  • 当找到符合条件的组合时,将其存储在 result 数组中,并更新 returnColumnSizesreturnSize

内存管理

  • main 函数中,释放动态分配的内存,避免内存泄漏。

复杂度分析

  • 时间复杂度 :O(target)。由于我们最多遍历到 target / 2,因此时间复杂度为线性。

  • 空间复杂度:O(1)。除了存储结果的空间外,只使用了常数级别的额外空间。

总结

通过滑动窗口算法,我们可以高效地解决这个问题。滑动窗口的核心思想是通过动态调整窗口的大小,找到满足条件的连续子序列。这种方法不仅代码简洁,而且时间复杂度较低,非常适合处理类似的问题。

希望这篇博客对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。

相关推荐
肆悟先生5 分钟前
3.16 含有可变参数的函数
c++·算法
步步为营DotNet10 分钟前
深度解析.NET中属性(Property)的幕后机制:优化数据访问与封装
java·算法·.net
Swift社区10 分钟前
LeetCode 454 - 四数相加 II
java·算法·leetcode
tokepson13 分钟前
反向传播
深度学习·算法·ai·反向传播
Xの哲學20 分钟前
Linux AQM 深度剖析: 拥塞控制
linux·服务器·算法·架构·边缘计算
艾醒23 分钟前
大模型原理剖析——突破LLM效率瓶颈:多标记预测(MTP)技术深度解析与实战
算法
智驱力人工智能23 分钟前
森林防火无人机火焰监测系统 构建“天空地”一体化智能防火体系 无人机火焰检测,支持红色火焰检测 城市高层建筑无人机火焰识别
人工智能·深度学习·opencv·算法·目标检测·无人机·边缘计算
多米Domi01124 分钟前
0x3f第12天 0-1背包
python·算法·leetcode·动态规划
我命由我1234526 分钟前
开发中的英语积累 P21:Parentable、Guideline、Manifest、Expire、Condition、Optimize
经验分享·笔记·学习·职场和发展·求职招聘·职场发展·学习方法
Bruce_kaizy30 分钟前
c++图论————最短路之Floyd&Dijkstra算法
c++·算法·图论