38. 外观数列

题目

「外观数列」是一个数位字符串序列,由递归公式定义:

countAndSay(1) = "1"
countAndSay(n)countAndSay(n-1) 的行程长度编码。

行程长度编码(RLE)是一种字符串压缩方法,其工作原理是通过将连续相同字符(重复两次或更多次)替换为字符重复次数(运行长度)和字符的串联。例如,要压缩字符串 “3322251”,我们将 “33” 用 “23” 替换,将 “222” 用 “32” 替换,将 “5” 用 “15” 替换并将 “1” 用 “11” 替换。因此压缩后字符串变为 “23321511”。

给定一个整数 n,返回外观数列的第 n 个元素。

示例 1:

输入:n = 4
输出:“1211”

解释:

countAndSay(1) = "1"
countAndSay(2) = "1" 的行程长度编码 = “11”
countAndSay(3) = "11" 的行程长度编码 = “21”
countAndSay(4) = "21" 的行程长度编码 = “1211”

示例 2:

输入:n = 1
输出:“1”

解释:

这是基本情况。

提示:

1 <= n <= 30

代码

完整代码

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

char* countAndSay(int n) {
    char* result = NULL;
    char* origin = NULL;
    if (n == 1) {
        return strdup("1");
    } else {
        origin = (char*)calloc(5000, sizeof(char));
        result = (char*)calloc(5000, sizeof(char));
        char nums[] = "0123456789";
        strcpy(result, "1");
        for (int i = 1; i < n; i++) {
            strcpy(origin, result);
            strcpy(result, "");
            int lastNum = origin[0] - '0';
            int lastNumCnt = 1;
            char new[4] = {'\0'};
            for (int j = 1; j < strlen(origin); j++) {
                if (nums[lastNum] != origin[j]) {
                    sprintf(new, "%d%d", lastNumCnt, lastNum);
                    strcat(result, new);
                    lastNum = origin[j] - '0';
                    lastNumCnt = 1;
                } else {
                    lastNumCnt++;
                }
            }
            sprintf(new, "%d%d", lastNumCnt, lastNum);
            strcat(result, new);
        }
    }
    free(origin);
    return result;
}

思路分析

这套代码用了字符串遍历和拼接的方法。

  • 首先,初始化基础情况,即当 n 为 1 时,直接返回 “1”。
  • 从第 2 个序列开始,每次根据前一个序列进行行程长度编码。
  • 使用两个字符串 originresult 来存储和构造新的序列。
  • 通过遍历 origin,计算每个字符的重复次数,并将其转换为新的子序列,最终拼接到 result 中。
  • 重复上述过程,直到生成第 n 个序列。

拆解分析

  1. 初始化和基础情况处理
if (n == 1) {
    return strdup("1");
}

当 n 为 1 时,直接返回 “1”。

  1. 初始化两个字符串 originresult
origin = (char*)calloc(5000, sizeof(char));
result = (char*)calloc(5000, sizeof(char));
strcpy(result, "1");

初始化两个字符串,用于存储和构造新的序列。

  1. 生成新的序列
for (int i = 1; i < n; i++) {
    strcpy(origin, result);
    strcpy(result, "");
    int lastNum = origin[0] - '0';
    int lastNumCnt = 1;
    char new[4] = {'\0'};
    for (int j = 1; j < strlen(origin); j++) {
        if (nums[lastNum] != origin[j]) {
            sprintf(new, "%d%d", lastNumCnt, lastNum);
            strcat(result, new);
            lastNum = origin[j] - '0';
            lastNumCnt = 1;
        } else {
            lastNumCnt++;
        }
    }
    sprintf(new, "%d%d", lastNumCnt, lastNum);
    strcat(result, new);
}

遍历 origin,计算每个字符的重复次数,并将其转换为新的子序列,最终拼接到 result 中。

复杂度分析

  • 时间复杂度:O(n * m),其中 n 为输入整数,m 为每个生成序列的长度。每次生成新的序列需要遍历前一个序列的所有字符。
  • 空间复杂度:O(m),用于存储生成的序列。

一题多解

方法2:使用递归的方式

完整代码

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

char nums[] = "0123456789";

char* nextRLE(char* s) {
    char* result = (char*)calloc(5000, sizeof(char));
    int lastNum = s[0] - '0';
    int lastNumCnt = 1;
    char new[4] = {'\0'};
    for (int j = 1; j < strlen(s); j++) {
        if (nums[lastNum] != s[j]) {
            sprintf(new, "%d%d", lastNumCnt, lastNum);
            strcat(result, new);
            lastNum = s[j] - '0';
            lastNumCnt = 1;
        } else {
            lastNumCnt++;
        }
    }
    sprintf(new, "%d%d", lastNumCnt, lastNum);
    strcat(result, new);
    free(s);
    return result;
}

char* countAndSay(int n) {
    char* result = strdup("1");
    if (n == 1) {
        return result;
    } else {
        for (int i = 1; i < n; i++) {
            result = nextRLE(result);
        }
    }
    return result;
}

思路分析

这套代码用了递归和字符串拼接的方法。

  • 定义一个辅助函数 nextRLE,用于生成给定字符串的下一个行程长度编码字符串。
  • countAndSay 函数中,从 “1” 开始,逐步调用 nextRLE,直到生成第 n 个序列。

拆解分析

  1. nextRLE函数
char* nextRLE(char* s) {
    char* result = (char*)calloc(5000, sizeof(char));
    int lastNum = s[0] - '0';
    int lastNumCnt = 1;
    char new[4] = {'\0'};
    for (int j = 1; j < strlen(s); j++) {
        if (nums[lastNum] != s[j]) {
            sprintf(new, "%d%d", lastNumCnt, lastNum);
            strcat(result, new);
            lastNum = s[j] - '0';
            lastNumCnt = 1;
        } else {
            lastNumCnt++;
        }
    }
    sprintf(new, "%d%d", lastNumCnt, lastNum);
    strcat(result, new);
    free(s);
    return result;
}

生成给定字符串的下一个行程长度编码字符串。

  1. countAndSay函数
char* countAndSay(int n) {
    char* result = strdup("1");
    if (n == 1) {
        return result;
    } else {
        for (int i = 1; i < n; i++) {
            result = nextRLE(result);
        }
    }
    return result;
}

逐步调用 nextRLE 函数,直到生成第 n 个序列。

复杂度分析

  • 时间复杂度:O(n * m),其中 n 为输入整数,m 为每个生成序列的长度。
  • 空间复杂度:O(m),用于存储生成的序列。

结果

正常

在这里插入图片描述

递归

在这里插入图片描述

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

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

相关文章

刷代码随想录有感(114):动态规划——最少数量的零钱换整

题干&#xff1a; 代码&#xff1a; class Solution { public:int coinChange(vector<int>& coins, int amount) {vector<int>dp(amount 1, INT_MAX);dp[0] 0;for(int i 0; i < coins.size(); i){for(int j coins[i]; j < amount; j){if(dp[j - coi…

【Linux】系统文件IO·文件描述符fd

前言 C语言文件接口 C 语言读写文件 1.C语言写入文件 2.C语言读取文件 stdin/stdout/stderr 系统文件IO 文件描述符fd&#xff1a; 文件描述符分配规则&#xff1a; 文件描述符fd&#xff1a; 前言 我们早在C语言中学习关于如何用代码来管理文件&#xff0c;比如文件的…

对于C++ 程序员来说,35岁魔咒是否存在?

大家常说程序员职业生涯会在35岁左右遇到所谓的“35岁魔咒”。这意味着在这个年龄段&#xff0c;程序员可能会面临就业不稳定或职业发展的挑战。对于C程序员来说&#xff0c;这个问题更加引人关注。 随着时间的推移&#xff0c;技术行业不断演进&#xff0c;新的编程语言层出不…

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 01:假想的编译器

这是一本老书&#xff0c;作者 Steve Maguire 在微软工作期间写了这本书&#xff0c;英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字&#xff0c;英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》&a…

34、shell数组+正则表达式命令

0、课前补充 jiafa () { result$(echo " $1 $2 " | bc ) print "%.2f\n" "$result" } ##保留小数点两位 薄弱加强点 a$(df -h | awk NR>1 {print $5} | tr -d %) echo "$a"一、数组 1.1、定义 数组的定义&am…

Native开发工具之应用开发编辑器打包发布(一)

Nuclide 是基于 Atom 之上构建的单独的一个包&#xff0c;其提供可编程性且社区非常活跃。它为 React Native、Hack 和 Flow 项目提供一流的开发环境。 2. Atom 官网&#xff1a;https://atom.io/ Github 项目地址&#xff1a;atom(https://github.com/atom) 文档&#xff1…

SpringBoot-注解@PropertiySource读取外部属性文件

ConfigurationProperties和Value两个注解能从配置文件中获取数据&#xff0c;但是前面讲了他们是从全局配置文件中获取&#xff0c;且只能从全局配置文件中获取&#xff0c;那么如果是一些数值类的数据放在全局配置文件里&#xff0c;是不怎么合适的&#xff0c;我们往往会把他…

gitlab 获取指定分支下指定路径文件夹的解决方案

第一步&#xff1a; 获取 accessToken 及你的 项目 id &#xff1a; 获取 accessToken ,点击用户头像进入setting 按图示操作&#xff0c;第 3 步 填写你发起请求的域名。 获取项目 id , 简单粗暴方案 进入 你项目仓库页面后 直接 源码搜索 project_id&#xff0c; value 就…

QT自定义标题栏窗口其一:实现拖动及可拉伸效果

1、效果 2、核心代码 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent<

Android intent 打开链接跳转到外部浏览

前言: 各位同学大家好, 最近接到一个比较诡异的需求 ,不是通常的webview 加URL显示网页 是需要跳转到外部浏览器 ,我这边处理好了就分享给大家 效果图 : 点几就跳转到外部浏览器 如图 具体代码实现: 点击打开链接并跳转外部浏览器方法 public void openBrowser(Con…

算法刷题总结

1. 排序算法 1.1 快速排序算法 public abstract class Sort<T extends Comparable<T>> {public abstract void sort(T[] array);protected boolean less(T first, T two) {return first.compareTo(two) < 0;}protected void swap(T[] array, int i, int j) {T…

《人生苦短,我用python·四》pybind11多场景使用

引言 Pybind11作为一个强大的工具&#xff0c;不仅可以轻松地将简单的C函数和类暴露给Python&#xff0c;还可以处理更复杂的场景&#xff0c;比如支持C标准库容器、处理C异常、以及自定义数据结构的转换。本文将深入介绍Pybind11的一些高级用法&#xff0c;帮助你在实际项目中…

修复 pprof ---node_exproter访问漏洞(go-pprof-leak)

前言&#xff1a; ** 在Go语言中&#xff0c;pprof和debug包是用来检测和避免goroutine泄漏&#xff0c;避免导致goroutine泄漏&#xff0c;进而消耗大量系统资源。不过对于安全而言确又存在一定风险&#xff0c;** 风险&#xff1a; 通过node_exporter web发现 190.168.46.1…

Unity Meta Quest 开发:关闭 MR 应用的安全边界

社区链接&#xff1a; SpatialXR社区&#xff1a;完整课程、项目下载、项目孵化宣发、答疑、投融资、专属圈子 &#x1f4d5;教程说明 这期教程我将介绍如何在应用中关闭 Quest 系统的安全边界。 视频讲解&#xff1a; https://www.bilibili.com/video/BV1Gm42157Zi 在 Unity…

DVWA 靶场 Weak Session IDs 通关解析

前言 DVWA代表Damn Vulnerable Web Application&#xff0c;是一个用于学习和练习Web应用程序漏洞的开源漏洞应用程序。它被设计成一个易于安装和配置的漏洞应用程序&#xff0c;旨在帮助安全专业人员和爱好者了解和熟悉不同类型的Web应用程序漏洞。 DVWA提供了一系列的漏洞场…

VirtualBox虚拟机声音设置

最近发现VirtualBox创建的Windows 10和11虚拟机没有声音&#xff0c;但是另外一个Windows 7的虚拟机确有声音&#xff0c;检查对比了一下虚拟机的声音设置&#xff0c;发现是Host Audio Driver的设置不一样&#xff0c;Windows10和11的是Default&#xff0c;而Windows7的是Puls…

【C++】初始化列表、匿名对象、static成员、友元、内部类

文章目录 一、初始化列表构造函数体赋值初始化列表explicit关键字 二、匿名对象三、static成员四、友元友元函数友元类 五、内部类六、练习题 一、初始化列表 构造函数体赋值 实际上&#xff0c;构造函数的函数体内&#xff0c;并不是对 对象 初始化的地方&#xff0c;而是对…

html做一个雷达图的软件

要实现一个在线输入数据并生成雷达图的功能&#xff0c;可以使用HTML表单和JavaScript来处理用户输入的数据。以下是一个示例代码&#xff0c;演示了如何实现这个功能&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"…

C++初学者指南第一步---13.聚合类型

C初学者指南第一步—13.聚合类型 文章目录 C初学者指南第一步---13.聚合类型1. 类型分类&#xff08;简化&#xff09;2. 如何定义和使用3. 为什么选择自定义类型/数据聚合&#xff1f;4. 聚合类型初始化5.混合6. 复制7. 值和引用的语义8.聚合的向量(std::vector)9.最令人烦恼的…

文件创建与查看

touch touch命令用于创建一个新的文件。 语法&#xff1a;touch Linux路径 其中路径可以是相对路径、绝对路径或者特殊路径符都可以。 改图展示了通过 touch test.txt 命令创建了一个 test.txt文件&#xff0c;其中深色的代表文件夹&#xff0c;白色的代表文件。 使用 ls -lh…