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

总结

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

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

相关推荐
利刃大大44 分钟前
【回溯+剪枝】找出所有子集的异或总和再求和 && 全排列Ⅱ
c++·算法·深度优先·剪枝
皮卡丘のcoding1 小时前
蓝桥杯备赛练习题01
职场和发展·蓝桥杯
Rachela_z2 小时前
代码随想录算法训练营第十四天| 二叉树2
数据结构·算法
细嗅蔷薇@2 小时前
迪杰斯特拉(Dijkstra)算法
数据结构·算法
追求源于热爱!2 小时前
记5(一元逻辑回归+线性分类器+多元逻辑回归
算法·机器学习·逻辑回归
不过四级不改名6772 小时前
蓝桥杯嵌入式uart,iic,adc_scan模版
职场和发展·蓝桥杯
ElseWhereR2 小时前
C++ 写一个简单的加减法计算器
开发语言·c++·算法
Smark.2 小时前
Gurobi基础语法之 addConstr, addConstrs, addQConstr, addMQConstr
算法
S-X-S2 小时前
算法总结-数组/字符串
java·数据结构·算法
Joyner20183 小时前
python-leetcode-从中序与后序遍历序列构造二叉树
算法·leetcode·职场和发展