组合总和及结果显示_20230827

本文详细介绍了如何使用回溯方法解决LeetCode上的组合总和问题,讨论了无循环和循环两种实现方式,并提供了C语言代码示例。重点在于处理集合的无序性和避免重复组合的生成。

组合总和-兼论回溯方法_20230827

  1. 前言

针对组合总和的不同方法讨论,本文引出两类常见的回溯结构模式,回溯方法是众所周知的知识,它是在计算过程中,对相邻前后状态的记忆及回退,引导程序进入历史某一状态,重新开始基本的计算。

  1. 问题描述

组合总和问题源于Leetcode习题练习,题目描述为:

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

本题目为典型求解集合问题,它不同于常规求解集合问题的地方在于,集合定义为无序状态,声明下面集合为同质集合,剔除同质集合或避免程序求出同质集合为程序需要解决的首要任务。题干中强调的,你可以按任意顺序返回这些组合,强调的也是需要满足这一规则。

<a,b,c>, <b,a,c>,<c,a,b>,<a,c,b><b,c,a><c,b,a>

具体看2个实际例子,

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例1当中[2,2,3],[3,2,2]及[2,3,2]视为同一解,在最终解结论中,需要罗列任一个即可。示例2当中[2,3,3],[3,2,3]及[3,3,2]视为同一解。

  1. 程序实现

以示例1进行过程描述,要实现目标值,可以选取或放弃集合中某元素,为了避免重复的集合重新,只能选取当前位置及后续位置的元素,禁止选取当前元素前的任何元素。这就需要施加条件对操作对象进行有效筛选,确保仅选取当前及后续的元素,禁止每次选择所有对象。

首先定义解结构,输出不同满足要求的组合,需要定义解的数量及每个解当中所含有的元素数量,为了程序方便,定义如下解结构。

声明的全局变量temp数组跟踪回溯过程中的元素, temp_size记录当前temp数组中所包含元素数量,也可以理解为当前数组的下一元素下标值。

ans数组中储存指针,它属于指针数组,对于每个有效的解,它都储存在某个一维数组中,那么一维数组的指针就储存在ans数组当中。ans_len记录当前解数量,elem_len数组记录每个解数量中包含的对象数目。

#define N 1001

int temp[N];
int temp_size;

/**
 * @brief State the structure of solution
 * 
 */
typedef struct answer
{
    int *ans[N];
    int  ans_len;
    int  elem_len[N];
}answer, *answer_ptr;

定义头文件combination_num.h

/**
 * @file combination_num.h
 * @author your name (you@domain.com)
 * @brief
 * https://leetcode.cn/problems/combination-sum/
 * @version 0.1
 * @date 2023-08-27
 *
 * @copyright Copyright (c) 2023
 *
 */
#ifndef COMBINATION_SUM_H
#define COMBINATION_SUM_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1001

int temp[N];
int temp_size;

/**
 * @brief It is a dynamic data structure
 * 
 */
typedef struct answer
{
    int *ans[N];
    int  ans_len;
    int  elem_len[N];
}answer, *answer_ptr;

void combination_sum(int *nums, int n, int index, int sub_num,int target, answer_ptr res);

void display_result(answer_ptr res);

#endif

我们加下来一一讨论回溯的两种实现方式以及实现的具体过程,第一种实现方式不采用循环语句,需要利用两个相邻的递归函数实现。

3-1. 无循环方式

    temp[temp_size++]=nums[index];
    combination_sum(nums,n,index,sub_num+nums[index],target,res);
    temp_size--;
    combination_sum(nums, n, index+1, sub_num, target, res);

combination_sum(nums,n,index,sub_num+nums[index],target,res)对下标为index的对象利用DFS方式递加,过程中判断是否等于target或大于target; temp_size–表示记录数组回退,求和中将剔除nums[index]元素; index+1表示跳过当前元素,仅计算对象的后续元素。

3-2. 循环方式

    for(i=index;i<n;i++)
    {
        temp[temp_size++]=nums[i];
        combination_sum(nums, n, i, sub_num + nums[i], target, res);
        temp_size--;
    }

循环方式中采用变量i来跟踪元素位置变化,规定元素起始位置为index,只有在index及之后的元素才能进入操作数范围,确保集合的唯一性。

无循环方式的实现程序,

/**
 * @file combination_num.c
 * @author your name (you@domain.com)
 * @brief
 * 
 * @date 2023-08-27
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef COMBINATION_SUM_C
#define COMBINATION_SUM_C
#include "combination_sum.h"

void combination_sum(int *nums, int n, int index, int sub_num, int target, answer_ptr res)
{
    if (sub_num > target)
    {
        return;
    }

    if (sub_num == target)
    {
        int *res_ptr;

        res_ptr=(int*)malloc(sizeof(int)*temp_size);
        memcpy(res_ptr, temp, sizeof(int) * temp_size);
        res->ans[res->ans_len]=res_ptr;
        res->elem_len[res->ans_len]=temp_size;
        res->ans_len+=1;

        return;        
    }
    
    if(index==n)
    {
        return;
    }

    temp[temp_size++]=nums[index];
    combination_sum(nums,n,index,sub_num+nums[index],target,res);
    temp_size--;
    combination_sum(nums, n, index+1, sub_num, target, res);
}

void display_result(answer_ptr res)
{
    int i;
    int j;

    for(i=0;i<res->ans_len;i++)
    {
        printf("{ ");
        for(j=0;j<res->elem_len[i];j++)
        {
            printf("%d ",res->ans[i][j]);
        }
        printf("},");
    }
}

#endif

循环方式的实现程序,

/**
 * @file combination_num.c
 * @author your name (you@domain.com)
 * @brief
 * 
 * @date 2023-08-27
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef COMBINATION_SUM_C
#define COMBINATION_SUM_C
#include "combination_sum.h"

void combination_sum(int *nums, int n, int index, int sub_num, int target, answer_ptr res)
{
    
    int i;

    if (sub_num > target)
    {
        return;
    }

    if (sub_num == target)
    {
        int *res_ptr;

        res_ptr=(int*)malloc(sizeof(int)*temp_size);
        memcpy(res_ptr, temp, sizeof(int) * temp_size);
        res->ans[res->ans_len]=res_ptr;
        res->elem_len[res->ans_len]=temp_size;
        res->ans_len+=1;

        return;        
    }
    
    if(index>=n)
    {
        return;
    }


    for(i=index;i<n;i++)
    {
        temp[temp_size++]=nums[i];
        combination_sum(nums, n, i, sub_num + nums[i], target, res);
        temp_size--;
    }
}

void display_result(answer_ptr res)
{
    int i;
    int j;

    for(i=0;i<res->ans_len;i++)
    {
        printf("{ ");
        for(j=0;j<res->elem_len[i];j++)
        {
            printf("%d ",res->ans[i][j]);
        }
        printf("},");
    }
}

#endif

  1. 小结

本问题针对组合总和问题解决过程中,阐述了回溯的两种不同形式,两类形式都可以取得相同效果,读者可以根据自身需要,选择其中之一作为解题方法。本博文仅仅针对解题新得进行记录。

参考资料:

https://leetcode.cn/problems/combination-sum/

<think>嗯,用户的问题是关于在MySQL中查询订单总和并在指定行显示,需要使用SUM和LIMIT来实现。首先,我需要回忆一下相关的SQL知识。记得SUM是聚合函数,通常和GROUP BY一起使用,而LIMIT用于限制返回的行数。但用户提到他们想用SUM和LIMIT一起,可能遇到了问题,比如SUM优先执行导致LIMIT不起作用。 根据引用[1],用户可能遇到了SUM和LIMIT优先级的问题。因为SUM会先执行,然后LIMIT才会应用,所以直接组合可能导致错误。例如,用户可能尝试先SUM再LIMIT,但结果可能不符合预期。需要子查询来先限制行数,再进行求和。 然后,用户的需求是查询订单总和并在指定行显示。可能的场景是用户有一个订单表,想要在某个子查询的结果上计算总和。例如,先获取最近的N条订单,然后计算这些订单的总和。这时候需要先通过子查询使用LIMIT获取指定行,然后在外部使用SUM。 需要考虑到子查询的结构是否正确,别名是否使用正确。比如在子查询中先选择需要的字段,应用ORDER BY和LIMIT,然后在外部使用SUM。例如,SELECT SUM(total) FROM (SELECT total FROM orders ORDER BY id DESC LIMIT 5) AS subquery; 这样就能先限制行数再求和。 另外,用户可能需要显示总和在指定行,比如在结果中同时显示某些订单和总和。这时候可能需要使用UNION ALL来合并两个查询的结果。例如,先选择前N行订单,然后加上一个总和行。但需要注意数据类型和列数的一致性。 还要注意,当使用UNION时,总和行可能需要用别名来匹配列名,比如用'总计'作为标识。同时,处理NULL值的情况,确保不影响SUM的结果。例如,引用[3]中的例子显示某些字段可能为NULL,SUM会忽略NULL,但需要确认是否符合用户需求。 最后,验证不同的方法是否有效,比如子查询方法和UNION方法,哪种更符合用户的实际需求。用户可能需要的是在同一个结果集中同时显示部分数据和总和,这时候可能需要使用WITH ROLLUP或者变量,但WITH ROLLUP通常与GROUP BY一起使用,可能不适合单独的总和。因此,UNION方法可能更直接。 需要提醒用户在使用LIMIT时注意排序,确保获取的是正确的指定行。例如,使用ORDER BY来明确排序依据,避免结果不确定性。此外,性能方面,子查询可能会影响效率,特别是当数据量大时,需要适当的索引优化。 总结可能的解决方案:使用子查询先限制行数再求和,或者使用UNION合并结果。同时,注意语法正确性,比如别名和括号的使用,确保查询不会报错。</think>### MySQL查询订单总和并在指定行显示的实现方法 #### 一、核心问题分析 1. **优先级冲突**:直接使用$SUM()$和$LIMIT$时,聚合函数会优先执行,导致$LIMIT$失效[^1] 2. **实现需求**:需要先限定数据范围再计算总和 3. **正确语法结构**:通过子查询建立正确的执行顺序 #### 二、标准实现方案 ```sql SELECT SUM(total_amount) AS order_total FROM ( SELECT total_amount FROM orders WHERE user_id = 1001 ORDER BY order_date DESC LIMIT 5 ) AS subquery; ``` #### 三、关键参数说明 | 参数 | 说明 | |------|------| | `total_amount` | 需要求和的字段 | | `ORDER BY` | 确定数据筛选顺序 | | `LIMIT 5` | 限定取最新5条记录 | | `subquery` | 必须的查询别名 | #### 四、特殊场景扩展 **在结果集中显示指定行和总和**: ```sql (SELECT order_no, total_amount FROM orders WHERE user_id = 1001 ORDER BY order_date DESC LIMIT 3) UNION ALL (SELECT '总计', SUM(total_amount) FROM orders WHERE user_id = 1001 ORDER BY order_date DESC LIMIT 3); ``` #### 五、注意事项 1. **索引优化**:建议在`order_date`字段建立索引 2. **空值处理**:当`total_amount`包含NULL值时,使用`IFNULL(total_amount,0)` 3. **性能影响**:大数据量时注意子查询性能
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值