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)。除了存储结果的空间外,只使用了常数级别的额外空间。

总结

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

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

相关推荐
会员源码网34 分钟前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
木心月转码ing1 小时前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
HelloReader2 小时前
Wi-Fi CSI 感知技术用无线信号“看见“室内的人
算法
颜酱5 小时前
二叉树分解问题思路解题模式
javascript·后端·算法
qianpeng8976 小时前
水声匹配场定位原理及实验
算法
董董灿是个攻城狮18 小时前
AI视觉连载8:传统 CV 之边缘检测
算法
AI软著研究员1 天前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish1 天前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱1 天前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
地平线开发者2 天前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶