oj第十二周训练——递归方法实现逆序

本文通过一个简单的递归程序实例介绍了如何使用递归方法实现整数逆序的功能,并附带了完整的C语言代码。文章还提供了输入输出示例以及递归方法的基本概念。

问题及代码

Description

你知道递归么?简单来说,递归就是函数自身对自身的调用,直到遇到终止条件,再对数据做逆向处理,下面就有一个递归的简单例子等你来处理。

#include <stdio.h>
void inverted(int); /*函数声明*/
int main()
{
    int n; /*需要逆序的整数*/
    scanf("%d",&n);
    inverted(n); /*调用逆序函数*/
    return 0;
}

void inverted(int n)
{
    if(n<10) /*当数字只剩一位的时候,即第一位数,输出,变为末位,返回*/
    {
        printf("%d",n);
        return;
    }
   /***************/      /*从后往前除以10取余输出,即当前n的最后一位*/

请在此补充缺失代码
    /***************/    /*继续调用逆序函数,每次调用都输出当前n的最后一位*/
    return;
}

Input

一个int型整数

Output

转换后的整数

Sample Input

1234567

Sample Output

7654321
/*烟台大学计算机学院 2016
作者: 马春澎
完成日期:2016年11月19日 */

#include <stdio.h>
void inverted(int); /*函数声明*/
int main()
{
    int n; /*需要逆序的整数*/
    scanf("%d",&n);
    inverted(n); /*调用逆序函数*/
    return 0;
}

void inverted(int n)
{
    if(n<10) /*当数字只剩一位的时候,即第一位数,输出,变为末位,返回*/
    {
        printf("%d",n);
        return;
    }
    else
    {
        printf("%d",n%10);
        inverted (n/10);
        return ;
    }
    return;
}
运算结果
知识点总结
递归方法的简单应用,让我们认识递归方法
学习心得
要明白每一步是如何实现的,实在不会可以在纸上画出流程图。

<think>嗯,用户想解决XTU OJ上的逆序数大数据问题,我之前看到过这个问题。首先,我得回忆一下逆序数的定义,就是在一个序列中,所有i<j但a[i]>a[j]的数对的个数。小数据的时候可以用双重循环暴力解决,比如冒泡排序的方法,时间复杂度是O(n²),但大数据的话n可能很大,比如到1e5,这时候O(n²)就不行了,肯定会超时。所以必须用更高效的算法。 这时候应该想到分治法,比如归并排序。因为在归并的过程中,可以统计逆序数。归并排序的时间复杂度是O(n log n),适合处理大数据。那具体怎么统计呢?比如在合并两个有序数组的时候,如果左边的元素比右边的大,那么左边剩下的所有元素都会和右边的当前元素构成逆序对。这一步需要仔细思考。 然后,我需要考虑代码的结构。归并排序的递归实现,每次分成左右两部分,分别排序,然后合并。合并的时候,统计逆序数。每次比较左右两边的元素,当左边当前元素大于右边当前元素时,逆序数增加左边剩余元素的数量。这部分是关键,需要正确计算。 还要注意数据范围,比如数组的大小,是否可能溢出,需要用long long来存储逆序数。另外,测试用例可能有多个,所以每次处理完一个用例后,要重置计数器和数组。 可能遇到的错误包括递归终止条件不正确,或者在合并过程中没有正确移动指针导致遗漏或重复计算。另外,临时数组的使用也需要正确,避免覆盖原数组的数据。 还有,用户提供的引用中提到,前置知识是归并排序,所以必须确保自己对归并排序的过程足够熟悉。可能需要画个图来理解合并过程中如何计算逆序数。例如,当左右两个子数组都是有序的,那么当左数组的某个元素大于右数组的某个元素时,左数组中该元素之后的所有元素都会比右数组当前元素大,因此逆序数要加上左数组剩余元素的个数。 测试一下这个思路是否正确。比如序列3 1 2,分成3和1 2。左半部分处理完后,合并时3和1比较,3>1,此时左数组剩余1个元素(即3),所以逆序数加1,然后处理右数组的2,此时3>2,逆序数再加1,总共2,正确。这样说明方法是可行的。 代码实现的时候,需要注意归并的辅助数组,以及在递归过程中传递数组的索引范围。每次合并时,传入左、中、右的索引,然后进行合并操作,并在过程中统计逆序数。同时,逆序数的变量可能需要作为全局变量或者通过指针传递,或者在函数中返回统计的结果。 最后,总结步骤:分治法,归并排序,合并时统计逆序数,处理大数据时用O(n log n)的时间复杂度。这样应该就能解决XTU OJ的大数据逆序问题。</think>### 逆序数(大数据)解题思路 #### 问题分析 逆序数定义为序列中所有满足 $i < j$ 且 $a_i > a_j$ 的数对数量。对于小数据(如 $n \leq 1000$),可用双重循环暴力枚举,时间复杂度为 $O(n^2)$[^4][^5]。但对于大数据(如 $n \leq 10^5$),暴力法会超时,需采用更高效的算法。 #### 核心算法:归并排序优化 归并排序的分治特性可高效统计逆序数: 1. **分治**:将数组递归拆分为左右两半。 2. **合并**:合并两个有序子数组时统计逆序数。若左半部分元素 $a_i$ 大于右半部分元素 $b_j$,则 $a_i$ 及其后所有左半元素均与 $b_j$ 构成逆序对[^3]。 $$逆序数增量 = mid - i + 1$$ #### 代码实现步骤 1. **递归分割**:将数组分解至单个元素。 2. **合并统计**:合并时比较左右子数组元素,计算逆序数。 3. **时间复杂度**:$O(n \log n)$,适用于 $n \leq 10^6$ 的数据规模。 示例代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX 100010 typedef long long ll; ll merge(int arr[], int temp[], int left, int mid, int right) { ll cnt = 0; int i = left, j = mid + 1, k = left; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; cnt += mid - i + 1; // 统计逆序数 } } while (i <= mid) temp[k++] = arr[i++]; while (j <= right) temp[k++] = arr[j++]; for (i = left; i <= right; i++) arr[i] = temp[i]; return cnt; } ll merge_sort(int arr[], int temp[], int left, int right) { ll cnt = 0; if (left < right) { int mid = left + (right - left) / 2; cnt += merge_sort(arr, temp, left, mid); cnt += merge_sort(arr, temp, mid + 1, right); cnt += merge(arr, temp, left, mid, right); } return cnt; } int main() { int n, arr[MAX], temp[MAX]; while (scanf("%d", &n) && n) { for (int i = 0; i < n; i++) scanf("%d", &arr[i]); printf("%lld\n", merge_sort(arr, temp, 0, n - 1)); } return 0; } ``` #### 关键优化点 1. **临时数组复用**:避免频繁内存分配。 2. **数据类型**:使用 `long long` 存储大数结果。 3. **边界处理**:递归终止条件为 `left < right`[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值