38. 考古学家

题目描述

有一个考古学家发现一个石碑,但是很可惜,发现时其已经断成多段,原地发现n个断口整齐的石碑碎片。为了破解石碑内容,考古学家希望有程序能帮忙计算复原后的石碑文字组合数,你能帮忙吗?

输入描述

第一行输入n,n表示石碑碎片的个数。

第二行依次输入石碑碎片上的文字内容s,共有n组。

输出描述

输出石碑文字的组合(按照升序排列),行末无多余空格。

用例

输入3
a b c
输出abc
acb
bac
bca
cab
cba
说明
输入3
a b a
输出aab
aba
baa
说明
一、问题分析

首先读题,仔细看描述中的内容,发现需求是

1.有一个考古学家发现一个石碑,但是很可惜,发现时其已经断成多段

2.原地发现n个断口整齐的石碑碎片

3.为了破解石碑内容,考古学家希望有程序能帮忙计算复原后的石碑文字组合数

4.输入描述:第一行输入n,n表示石碑碎片的个数。

第二行依次输入石碑碎片上的文字内容s,共有n组。

5.输出描述:输出石碑文字的组合(按照升序排列),行末无多余空格。

二、解题思路

1.首先我们读取碎片个数int n;

scanf("%d", &n);

2.然后我们读取文字内容,存储为一个二维字符数组(通过动态分配内存实现)

char **fragments = (char **)malloc(n * sizeof(char *));

for(int i = 0; i < n; i++) {

fragments[i] = (char *)malloc(100 * sizeof(char));

scanf("%s", fragments[i]);

}

3.然后通过递归的方式手动生成所有可能的碎片文字排列组合情况,将这些排列组合存储在另一个动态分配内存的二维字符数组中。

char **result = NULL;

int resultSize = 0;

permute(fragments, 0, n, &result, &resultSize);

4.之后对这些排列组合进行排序

qsort(result, resultSize, sizeof(char *), compare);

5.排序后去除重复的组合

removeDuplicates(&result, &resultSize);

6.之后逐行输出这些排列组合

for(int i = 0; i < resultSize; i++) {

printf("%s\n", result[i]);

free(result[i]);

}

7.释放动态分配的内存避免内存泄漏

free(fragments);

free(result);

return 0;

8.使用到的库有标准库,标准输入输出库,字符串处理库

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

9.定义一个交换函数,用于交换两个字符指针所指向的字符串,在生成排列组合的过程中,通过交换指针指向的字符串来改变顺序,从而得到不同的排列情况。它接受两个二级字符指针作为参数,通过中间临时指针temp实现两个指针所指向字符串的交换。

void swap(char **a, char **b) {

char *temp = *a;

*a = *b;

*b = temp;

}

10.生成排列组合函数,这是一个递归函数,用于生成给定字符串数组fragments的所有全排列情况,并将结果存储到动态分配内存的result数组中,同时通过resultSize指针记录结果数组的大小(元素个数)。

递归终止条件:当start参数等于size - 1时,表示已经固定了前面所有位置的元素,当前位置就是最后一个位置了,此时已经生成了一种完整的排列组合。首先为这个新的排列组合分配足够的内存空间(根据每个碎片字符串长度和碎片个数计算所需字节数,额外加1是为了存储字符串结束符\0),然后通过循环将各个碎片字符串拼接起来形成一个完整的排列组合字符串newPerm。接着使用realloc函数动态调整result数组的内存大小,为新的排列组合字符串分配空间,并将其存储到result数组中,同时更新resultSize值。

递归生成排列组合部分:在start小于size - 1时,通过循环将当前位置start的元素与它后面的元素依次交换(通过调用swap函数),然后对剩余的元素(即从start + 1位置开始)递归调用permute函数来生成所有可能的排列情况,在一次递归调用返回后,再将交换的元素交换回来,回复原来的顺序,继续下一次交换和递归调用,以此类推,最终生成所有的排列组合情况。

void permute(char **fragments, int start, int size, char ***result, int *resultSize) {

if(start == size - 1) {

char *newPerm = (char *)malloc((strlen(fragments[0]) * size + 1) * sizeof(char));

newPerm[0] = '\0';

for(int i = 0; i < size; i++) {

strcat(newPerm, fragments[i]);

}

(*result) = (char **)realloc(*result, (*resultSize + 1) * sizeof(char **));

(*result)[*resultSize] = newPerm;

(*resultSize)++;

return;

}

for(int i = start; i < size; i++) {

swar(&fragments[start], &fragments[i]);

permute(fragments, start + 1, size, result, resultSize);

swap(&fragments[start], &fragments[i]);

}

}

11.比较函数,为qsort排序函数提供自定义的比较规则。qsort函数要求传入一个比较函数指针,用于比较两个元素的大小关系。在这里,比较的元素是字符指针(指向字符串),所以先通过*(char **)a和*(char **)b解引用得到实际的字符指针,再使用strcmp函数比较这两个指针所指向的字符串的大小(按照字典序比较),返回比较结果,供qsort函数根据这个结果对数组元素进行排序。

int compare(const void *a, const void *b) {

return strcmp(*(char **)a, *(char **)b);

}

12.去重函数,用于去除result数组中的重复字符串。通过循环遍历result数组,比较相邻的两个字符串(使用strcmp函数),如果不相等,就将当前字符串保留(将其复制到索引为j的位置,同时j自增1);如果相等,说明是重复的字符串,就释放其占用的内存空间(通过free函数)。最后将最后一个字符串也添加到去重后的数组中,并更新resultSize的值为去重后的数组元素个数,实现去重功能。

void removeDuplicates(char ***result, int *resultSize) {

int i, j;

for(int i = 0, j = 0; i < *resultSize - 1; i++) {

if(strcmp((*result)[i], (*result)[i + 1]) != 0) {

(*result)[j++] = (*result)[i];

}else {

free((*result)[i]);

}

}

(*result)[j++] = (*result)[*resultSize - 1];

*resultSize = j;

}

三、具体步骤

使用的语言是C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 交换两个字符串
void swap(char **a, char **b) {
    char *temp = *a;
    *a = *b;
    *b = temp;
}

// 生成全排列的函数,采用递归的方式
void permute(char **fragments, int start, int size, char ***result, int *resultSize) {
    if (start == size - 1) {
        // 为新的排列组合分配内存空间
        char *newPerm = (char *)malloc((strlen(fragments[0]) * size + 1) * sizeof(char));
        newPerm[0] = '\0';
        for (int i = 0; i < size; i++) {
            strcat(newPerm, fragments[i]);
        }

        // 将新的排列组合添加到结果数组中
        (*result) = (char **)realloc(*result, (*resultSize + 1) * sizeof(char **));
        (*result)[*resultSize] = newPerm;
        (*resultSize)++;
        return;
    }

    for (int i = start; i < size; i++) {
        swap(&fragments[start], &fragments[i]);
        permute(fragments, start + 1, size, result, resultSize);
        swap(&fragments[start], &fragments[i]);
    }
}

// 比较两个字符串指针指向的字符串是否相等
int compare(const void *a, const void *b) {
    return strcmp(*(char **)a, *(char **)b);
}

// 去除结果数组中的重复字符串
void removeDuplicates(char ***result, int *resultSize) {
    int i, j;
    for (i = 0, j = 0; i < *resultSize - 1; i++) {
        if (strcmp((*result)[i], (*result)[i + 1])!= 0) {
            (*result)[j++] = (*result)[i];
        } else {
            free((*result)[i]);
        }
    }
    (*result)[j++] = (*result)[*resultSize - 1];
    *resultSize = j;
}

int main() {
    int n;
    scanf("%d", &n);
    char **fragments = (char **)malloc(n * sizeof(char *));
    for (int i = 0; i < n; i++) {
        fragments[i] = (char *)malloc(100 * sizeof(char));  // 假设每个碎片字符串最长100个字符,可根据实际调整
        scanf("%s", fragments[i]);
    }

    char **result = NULL;
    int resultSize = 0;
    permute(fragments, 0, n, &result, &resultSize);

    // 排序
    qsort(result, resultSize, sizeof(char *), compare);
    // 去重
    removeDuplicates(&result, &resultSize);

    for (int i = 0; i < resultSize; i++) {
        printf("%s\n", result[i]);
        free(result[i]);
    }
    free(fragments);
    free(result);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947882.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JVM】总结篇-字节码篇

字节码篇 Java虚拟机的生命周期 JVM的组成 Java虚拟机的体系结构 什么是Java虚拟机 虚拟机&#xff1a;指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 &#xff0c;是物理机的软件实现。常用的虚拟机有VMWare&#xff0c;Visual Box&…

Springboot日志打印、SpringBoot集成Log4j2(附源码)、异步日志

文章目录 一、Log4j2介绍1.1、常用日志框架1.2、为什么选用log4j2 二、Log4j2整合步骤2.1、引入jar包2.2、配置文件2.3、配置文件模版 三、配置参数简介3.1、日志级别3.2、日志格式&#xff08;PatternLayout&#xff09;3.3、Appenders组件列表3.3.1、Console3.3.2、File3.3.3…

上传本地项目或文件到SVN服务器(图片讲解,超简单)

上传本地项目或文件到SVN服务器&#xff08;图片讲解&#xff0c;超简单&#xff09; 1、使用TortoiseSVN2、输入SVN远程仓库地址3、添加文件或文件夹 需求&#xff1a;将本地的文件上传到SVN服务器上指定路径。前提&#xff1a;已经安装好TortoiseSVN 1、使用TortoiseSVN 右…

使用 HEIC/HEIF 编码器将 HEIC 转换为 JPEG

随着iOS 11之后新的HEIF图像格式的发布&#xff0c;在当前几乎所有软件仅支持JPEG图像而不支持HEIC图像的环境下&#xff0c;这对Apple来说可能是一个巨大的挑战。不过&#xff0c;仍有一些方法可以为有需要的用户打开、查看、传输或转换iOS 11 HEIC 照片格式。本文将向您介绍 …

基于JAVA+SSM的教学资料管理系统

基于JAVASSM的教学资料管理系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; 哈喽兄弟们&a…

stm32 移植RTL8201F(正点原子例程为例)

最近在工作中需要使用RTL8201F&#xff0c;在网上找了很多帖子&#xff0c;没有找到合适的&#xff0c;自己翻资料移植了一个。 模板工程使用的是正点原子的f407探索版的例程&#xff0c;原子使用的是LAN8720,需要把他的驱动修改成为我们自己用的RTL8201F。 1.将PHY_TYPE改成我…

RK3588+麒麟国产系统+FPGA+AI在电力和轨道交通视觉与采集系统的应用

工业视觉识别系统厂家提供的功能主要包括&#xff1a; 这些厂家通过先进的视觉识别技术&#xff0c;实现图像的采集、处理与分析。系统能够自动化地完成质量检测、物料分拣、设备监控等任务&#xff0c;显著提升生产效率和产品质量。同时&#xff0c;系统具备高度的灵活性和可扩…

Linux umami网站统计工具自定义API开发

Linux umami网站统计工具自定义API开发 一、src/queries/analytics/下添加调用sql查询文件&#xff1a;二、src/queries/index.js文件中增加导出模块内容&#xff1a;三、src/pages/api/下根据目录添加接口方法文件&#xff1a;四、构建项目&#xff0c;启动。1、到umami目录&a…

Meta 的新策略,将 AI 生成的角色整合到其社交媒体平台

一、Meta新年规划及引人注目的举措 多元规划背景&#xff1a;在新的一年&#xff0c;Meta制定了多维度的战略规划&#xff0c;旨在巩固并拓展其在科技领域的影响力。增强现实与元宇宙是其长期布局的重点方向&#xff0c;期望借此塑造未来互联网的交互形态&#xff1b;面对TikTo…

微信小程序滑动解锁、滑动验证

微信小程序简单滑动解锁 效果 通过 movable-view &#xff08;可移动的视图容器&#xff0c;在页面中可以拖拽滑动&#xff09;实现的简单微信小程序滑动验证 movable-view 官方说明&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/component/movable-view.ht…

SWM221系列芯片之电机应用及控制

经过对SWM221系列的强大性能及外设资源&#xff0c;TFTLCD彩屏显示及控制进行了整体介绍后&#xff0c;新迎来我们的电控篇---SWM221系列芯片之电机应用及控制。在微控制器市场面临性能、集成度与成本挑战的当下&#xff0c;SWM221系列芯片以其卓越性能与创新设计&#xff0c;受…

软考教材重点内容 信息安全工程师 第 12 章网络安全审计技术原理与应用

12.1.1 网络安全审计概念 网络安全审计是指对网络信息系统的安全相关活动信息进行获取、记录、存储、分析和利用的工作。网络安全审计的作用在于建立“事后”安全保障措施&#xff0c;保存网络安全事件及行为信息&#xff0c;为网络安全事件分析提供线索及证据&#xff0c;以便…

代码随想录算法训练营day21

代码随想录算法训练营 —day21 文章目录 代码随想录算法训练营前言一、669. 修剪二叉搜索树递归法迭代法 二、108.将有序数组转换为二叉搜索树递归法迭代法 三、538.把二叉搜索树转换为累加树递归法 总结 前言 今天是算法营的第21天&#xff0c;希望自己能够坚持下来&#xf…

Jetson系列部署YOLOv8模型教程

简介 NVIDIA Jetson系列是专为边缘计算设计的紧凑型计算模块&#xff0c;其目标用户为AI开发者、嵌入式系统工程师以及需要在设备端实时进行数据处理与AI推断的创新者。通过提供灵活的硬件平台&#xff0c;结合NVIDIA强大的GPU计算资源&#xff0c;Jetson系列能够支持复杂的机…

Python 3 与 Python 2 的主要区别

文章目录 1. 语法与关键字print 函数整数除法 2. 字符串处理默认字符串类型字符串格式化 3. 输入函数4. 迭代器和生成器range 函数map, filter, zip 5. 标准库变化urllib 模块configparser 模块 6. 异常处理7. 移除的功能8. 其他重要改进数据库操作多线程与并发类型注解 9. 总结…

word中编号统一格式

不要手敲编号&#xff0c;要利用工具来。要善于利用多级编号和编号&#xff0c;分别对标题和段落进行组织 尤其是段落和标题特别多的时候&#xff0c;像毕设、标书这些 为什么呢&#xff1f;因为这样更方便修改&#xff0c;后续的增加和删除段落&#xff0c;编号会自动排列&am…

MySQL8安装与卸载

1.下载mysql MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/ 2.解压mysql安装包 解压到自己定义的目录&#xff0c;这里解压就是安装&#xff0c;解压后的路径不要有空格和中文。 3.配置环境变量 配置环境变量可以方便电脑在任何的路径…

牛客网刷题 ——C语言初阶——JZ15 二进制中1的个数

1.题目描述 题目OJ链接 描述 输入一个整数 n &#xff0c;输出该数32位二进制表示中1的个数。其中负数用补码表示。 2.思路 求2进制中1的个数&#xff0c;可以转换为求每一位&#xff0c;1的个数&#xff0c;1&1还是1 所以判断如果该数值&1为真&#xff0c;我们就co…

SAP物料主数据界面增加客制化字段、客制化页签的方式

文章目录 前言一、不增加页签&#xff0c;只增加客制化字段二、增加物料主数据页签 前言 【SAP系统MM模块研究】 #SAP #MM #物料 #客制化 #物料主数据 项目上难免会遇到客户要在物料主数据的界面上&#xff0c;增加新字段的需求。 实现方式有&#xff1a; &#xff08;1&…

十一、Vue 自定义指令详解

文章目录 一、自定义指令概念二、自定义指令的基本语法全局自定义指令局部自定义指令三、指令钩子函数bindinsertedupdatecomponentUpdatedunbind四、指令的参数传递简单参数传递动态参数传递五、自定义指令的应用场景权限控制动画效果第三方库集成六、自定义指令的双向绑定双向…