华为OJ:字符逆序和单词翻转

本文介绍了一种实现字符串及其单词的反转方法,通过C++代码详细解释了如何分别对整个字符串及单词进行翻转,并展示了实际应用过程中的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

将一个字符串str的内容颠倒过来,并输出。str的长度不超过100个字符。 如:输入“I am a student”,输出“tneduts a ma I”。

  输入参数:

inputString:输入的字符串

 

返回值:

输出转换好的逆序字符串

需要注意的是,该题和单词翻转之间的区别!单词翻转输入“I am a student.”,则输出“student.a am I”。


#include<iostream>

#include"stdio.h"
#include"string.h"
using namespace std;
/* 字符串反转
*/
void reverseStr(char* str, int i, int j)
{
	for (; i < j; i++, j--)
	{
		char tmp;
		tmp = str[i];
		str[i] = str[j];
		str[j] = tmp;
	}
	return;
}

/* 句子反转
*/
void reverseWords(char* str)
{
	int i = 0;
	char* subStrStart;
	char* subStrEnd;
	char* currentPos;

	currentPos = str;
	while (*currentPos != '\0')
	{
		subStrStart = currentPos;
		while (*currentPos != ' ' && * currentPos != '\0')
			currentPos++;
		subStrEnd = currentPos - 1;
		cout << (subStrEnd - str) << endl;// 注意此处,字符做减法的结果!!! ???可以直接得到位置信息???记录待翻转字符的起始和终点位置!
		reverseStr(str, (int)(subStrStart - str), (int)(subStrEnd - str));
		currentPos++;
	}
	return;
}






int main(int argc, char **argv)
{
	/*char test[5]="cd";
	char test2[10]="abcd";
	cout<<(test2-test)<<endl;*/

	char str[20];// "I am a student.";
	gets_s(str);// >> endl;
	//进行单词的逆序
	int Len = strlen(str);
	//char *temp;
	for (int i = Len-1; i >=0; i--)
	{
		cout << str[i];
	}
	//reverseStr(str, 0, strlen(str) - 1);//这个是单词翻转
	//reverseWords(str);//
	//printf("%s\n", str);
	return 0;


}

注意两者的区别!



<think>嗯,用户想解决XTU OJ上的逆序数大数据问题,我之前看到过这个问题。首先,我得回忆一下逆序数的定义,就是在一个序列中,所有i<j但a[i]>a[j]的数对的个数。小数据的时候可以用双重循环暴力解决,比如冒泡排序的方法,时间复杂度是O(n²),但大数据的话n可能很大,比如到1e5,这时候O(n²)就不行了,肯定会超时。所以必须用更高效的算法。 这时候应该想到分治法,比如归并排序。因为在归并的过程中,可以统计逆序数。归并排序的时间复杂度是O(n log n),适合处理大数据。那具体怎么统计呢?比如在合并两个有序数组的时候,如果左边的元素比右边的大,那么左边剩下的所有元素都会右边的当前元素构成逆序对。这一步需要仔细思考。 然后,我需要考虑代码的结构。归并排序的递归实现,每次分成左右两部分,分别排序,然后合并。合并的时候,统计逆序数。每次比较左右两边的元素,当左边当前元素大于右边当前元素时,逆序数增加左边剩余元素的数量。这部分是关键,需要正确计算。 还要注意数据范围,比如数组的大小,是否可能溢出,需要用long long来存储逆序数。另外,测试用例可能有多个,所以每次处理完一个用例后,要重置计数器数组。 可能遇到的错误包括递归终止条件不正确,或者在合并过程中没有正确移动指针导致遗漏或重复计算。另外,临时数组的使用也需要正确,避免覆盖原数组的数据。 还有,用户提供的引用中提到,前置知识是归并排序,所以必须确保自己对归并排序的过程足够熟悉。可能需要画个图来理解合并过程中如何计算逆序数。例如,当左右两个子数组都是有序的,那么当左数组的某个元素大于右数组的某个元素时,左数组中该元素之后的所有元素都会比右数组当前元素大,因此逆序数要加上左数组剩余元素的个数。 测试一下这个思路是否正确。比如序列3 1 2,分成31 2。左半部分处理完后,合并时31比较,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、付费专栏及课程。

余额充值