L58.【LeetCode题解】模拟算法习题集1(Z 字形变换、外观数列)

目录

1.Z 字形变换

方法1: 模拟

代码

提交结果

方法2:优化后的模拟

代码

提交结果

2.外观数列

方法1:模拟

代码

提交结果

方法2:打表

知识回顾

代码


1.Z 字形变换

https://leetcode.cn/problems/zigzag-conversion/

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:

输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"

示例 2:

输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I

示例 3:

输入:s = "A", numRows = 1
输出:"A"

提示:

  • 1 <= s.length <= 1000
  • s 由英文字母(小写和大写)、',''.' 组成
  • 1 <= numRows <= 1000

方法1: 模拟

Z 字形图示(其实看起来是N字形)

由于s.length和numRows的取值范围比较窄,因此可以创建一个1000*1000的char数组(不放心可以设大一些)

将连在一起的Z字形拆分成形状相同的部分

可以算出每一部分列数part_size_col为part_size-numRows+1,行数为numRows

可以算出每一部分字符的个数都是2 * numRows - 2个 

对于每一个部分,填字符分两步:1.竖着填 2.斜着填

最后打印vector<string>时要算清右多少行

先算算有多少个完整的部分:s.size()/part_size,它们一共占(s.size()/part_size)*part_size_col行,剩下来残缺的部分不超过part_size_col行,因此可以按(s.size()/part_size)*part_size_col+part_size_col来控制行所以

代码

注:numRows == 1要特殊处理

class Solution {
public:string convert(string s, int numRows){if (numRows==1){return s;}char arr[1010][1010];string ret;memset(arr, '\0', sizeof(arr));int row = 0;int col = 0;int part_size = 2 * numRows - 2;int part_size_col=part_size-numRows+1;int total_col=(s.size()/part_size)*part_size_col+part_size_col;for (int i = 0; i < s.size(); i++){if (i % part_size >= 0 && i % part_size <= numRows - 1){//竖着填arr[row][col] = s[i];row++;}else{//斜着填arr[row][col] = s[i];row--;col++;}if (i % part_size == numRows - 1){col++;row = numRows - 2;}}for (int i = 0; i < numRows; i++){for (int j = 0; j <total_col; j++){if (arr[i][j] != '\0')ret.push_back(arr[i][j]);}}return ret;}
};

提交结果

方法2:优化后的模拟

可使用模拟算法解的绝大部分题的优化方法是找规律

由特殊到一般,以s = "PAYPALISHIRING", numRows = 4为例,将字符在字符串中对应的下标填写到二维数组中

0  6  12  
1 57 1113  
24 810    
3  9     

分行看规律:

第0行:0,6,12

第n-1行:3,9

会发现第0行和第n-1行的相邻元素都差6,而6是2 * numRows - 2的值(可自行多找一个样例验证)

第1行~第n-2行:

两两一组看:

第1行: 1,5,    7,11,    13

第2行:2,4,    8,10

可得出如下规律:第k行: k,d-k,    k+d,2d-k,    k+2d,3d-k,......,k+nd,(n+1)d-k,其中(n+1)d-k<s.size()

代码

注:numRows == 1要特殊处理

class Solution {
public:string convert(string s, int numRows){if (numRows == 1)return s;string ret;int d = 2 * numRows - 2;//第0行int firstrow_i = 0;while (firstrow_i < s.size()){ret.push_back(s[firstrow_i]);firstrow_i += d;}//第1~(numRows-2)行for (int row = 1; row < numRows-1; row++){int i = row;while (i < s.size()){ret.push_back(s[i]);if (i + d - 2 * row < s.size())ret.push_back(s[i + d - 2 * row]);i += d;}}//第numRows-1行int lastrow_i = numRows - 1;while (lastrow_i < s.size()){ret.push_back(s[lastrow_i]);lastrow_i += d;}return ret;}
};

提交结果

2.外观数列

https://leetcode.cn/problems/count-and-say/

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

  • 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

    进阶:你能迭代解决该问题吗?

    方法1:模拟

    countAndSay(1) = "1",countAndSay(2)应该表示"1",即1个1,所以countAndSay(2)="11"

    countAndSay(3)应该表示"11",即2个1,所以countAndSay(3)="21"

    countAndSay(4)应该表示"21",即1个2,1个1,所以countAndSay(4)="1211"

    countAndSay(5)应该表示"1211",即1个1,1个2,2个1,所以countAndSay(4)="111221"

    循环即可,

    代码

    class Solution {
    public:string countAndSay(int n)//非递归,使用vector<string>存储从1~n的外观数列{vector<string> arr;arr.push_back("");arr.push_back("1");for (int i = 2; i <= n; i++){string tmp;int num = 0;char ch = arr[i - 1][0];for (int j = 0; j < arr[i - 1].size(); j++){if (arr[i - 1][j] == ch)num++;else{tmp = tmp + to_string(num);tmp.push_back(ch);ch = arr[i - 1][j];num = 1;}}if (num){tmp = tmp + to_string(num);tmp.push_back(ch);}arr.push_back(tmp);}return arr[n];}
    };

    提交结果

    或者不使用vector<string>,只保留第n个外观数列

    class Solution {
    public:string countAndSay(int n)//非递归,只保留第n个外观数列{string s="1";for (int i = 2; i <= n; i++){string tmp;int num = 0;char ch = s[0];for (int j = 0; j < s.size(); j++){if (s[j] == ch)num++;else{tmp = tmp + to_string(num);tmp.push_back(ch);ch = s[j];num = 1;}}if (num){tmp = tmp + to_string(num);tmp.push_back(ch);}s=tmp;}return s;}
    };
    

    提交结果:

     

    或者使用双指针:

    以"111221"为例:

    left和right之间1的个数为right-left

    class Solution {
    public:string countAndSay(int n)//双指针{string s = "1";for (int i = 2; i <= n; i++){string tmp;int left = 0;int right = 0;while (1){if (s[left] == s[right]){right++;if (right == s.size()){tmp = tmp + to_string(right - left);tmp.push_back(s[left]);break;}}else{tmp = tmp + to_string(right - left);tmp.push_back(s[left]);left = right;}}s = tmp;}return s;}
    };

    提交结果:

    方法2:打表

    1≤n≤30,由于n较小,因此可以批量生成前30个外观数列并存储到文件中

    知识回顾

    74.【C语言】文件操作(1)

    75.【C语言】文件操作(2)

    77.【C语言】文件操作(3)

    79.【C语言】文件操作(4)

    88.【C语言】文件操作(5)

    89.【C语言】文件操作(6)

    代码

    结果存储在result.txt中

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    #include <vector>
    #include <string>
    using namespace std;
    int main()//打表
    {vector<string> arr;arr.push_back("");//占位,可以任意写,n>0,不会访问到table[0]arr.push_back("1");//使用方法1的代码for (int i = 2; i <= 30; i++){string tmp;int num = 0;char ch = arr[i - 1][0];for (int j = 0; j < arr[i - 1].size(); j++){if (arr[i - 1][j] == ch)num++;else{tmp = tmp + to_string(num);tmp.push_back(ch);ch = arr[i - 1][j];num = 1;}}if (num){tmp = tmp + to_string(num);tmp.push_back(ch);}arr.push_back(tmp);}//将arr字符串写入文件中FILE* fptr = fopen("result.txt", "w");char str1[] = "vector<string> table={";fprintf(fptr, "%s", str1);for (auto s : arr){fprintf(fptr, "\"%s\",\n",s.c_str());}fseek(fptr, -1, SEEK_CUR);//回退一个字节fprintf(fptr, "};");//覆盖结尾的逗号fclose(fptr);
    }

    生成结果:

    之后粘贴到leetcode上:

     最后返回table[n]即可

    提交结果:

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

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    Flink MySQL CDC 环境配置与验证

    一、MySQL 服务器配置详解 1. 启用二进制日志&#xff08;Binlog&#xff09; MySQL CDC 依赖二进制日志获取增量数据&#xff0c;需在 MySQL 配置文件&#xff08;my.cnf 或 my.ini&#xff09;中添加以下配置&#xff1a; # 启用二进制日志 log-binmysql-bin # 二进制日志…

    如何查看自己电脑的CUDA版本?

    在搜索栏输入命令提示符 打开 输入 nvidia-smi图片中的两个是CUDA版本和显卡的信息

    opencv使用 GStreamer 硬解码和 CUDA 加速的方案

    在Conda环境中从源代码编译OpenCV&#xff08;支持CUDA和GStreamer&#xff09; 以下是完整的方案步骤&#xff0c;包括必要的依赖库安装过程&#xff1a; 1. 安装Miniconda&#xff08;如果尚未安装&#xff09; # 下载Miniconda安装脚本 wget https://repo.anaconda.com/m…

    Java面试宝典:多线程一

    1. run() vs start() 陷阱题 下面程序的运行结果 public static void main(String[] args) {Thread t = new Thread(

    【CSS-14-基础样式表Base.css】如何编写高质量的Base.css:前端样式重置与基础规范指南

    在前端开发中&#xff0c;Base.css&#xff08;也称为重置样式表或基础样式表&#xff09;是整个项目样式的基石。它负责消除浏览器默认样式的差异&#xff0c;建立统一的样式基准&#xff0c;为后续开发提供一致的起点。一个精心设计的Base.css能够显著提高开发效率&#xff0…

    探索Python数据科学工具链NumPyPandas与Scikit-learn

    NumPy&#xff1a;数值计算的基石 NumPy是Python中用于科学计算的核心库&#xff0c;它提供了一个强大的N维数组对象&#xff0c;以及大量的数学函数库&#xff0c;能够高效地进行向量和矩阵运算。对于数据科学家而言&#xff0c;掌握NumPy是进行数据处理和算法实现的基础。 创…

    八股学习(三)---MySQL

    一、MySQL中的回表是什么&#xff1f;我的回答&#xff1a;MySQL回表指的是在查询使用非聚簇索引也就是二级索引时&#xff0c;叶子节点只存储了索引列的值和主键Id&#xff0c;若要查询其他字段&#xff0c;就要根据主键去聚簇索引查询完整的数据。这个过程就是回表。比如用na…

    NeighborGeo:基于邻居的IP地理定位(一)

    NeighborGeo:基于neighbors的IP地理定位 X. Wang, D. Zhao, X. Liu, Z. Zhang, T. Zhao, NeighborGeo: IP geolocation based on neighbors, Comput. Netw. 257 (2025) 110896, Abstract IP地址定位在网络安全、电子商务、社交媒体等领域至关重要。当前主流的图神经网络方法…

    MySQL 8.0:窗口函数

    一、基础知识 定义 窗口函数&#xff08;Window Function&#xff09;对查询结果集的子集&#xff08;“窗口”&#xff09;进行计算&#xff0c;保留原始行而非聚合为单行&#xff0c;适合复杂分析&#xff08;如排名、累积和&#xff09;。 基本语法&#xff1a; 函数名() OV…

    AI 深度学习面试题学习

    1.神经网络 1.1各个激活函数的优缺点? 1.2为什么ReLU常用于神经网络的激活函数? 1.在前向传播和反向传播过程中,ReLU相比于Sigmoid等激活函数计算量小; 2.避免梯度消失问题。对于深层网络,Sigmoid函数反向传播时,很容易就会出现梯度消失问题(在Sigmoid接近饱和区时,变换…

    遇到该问题:kex_exchange_identification: read: Connection reset`的解决办法

    kex_exchange_identification: read: Connection reset 是一个非常常见的 SSH 连接错误。它表明在 SSH 客户端和服务器建立安全连接的初始阶段&#xff08;密钥交换&#xff0c;Key Exchange&#xff09;&#xff0c;连接就被对方&#xff08;服务器&#xff09;强制关闭了。 …

    (论文蒸馏)语言模型中的多模态思维链推理

    &#xff08;论文总结&#xff09;语言模型中的多模态思维链推理 论文名称研究背景动机主要贡献研究细节两阶段框架实验结果促进收敛性摆脱人工标注错误分析与未来前景 论文名称 Multimodal Chain-of-Thought Reasoning in Language Models http://arxiv.org/abs/2302.00923 …

    React Native 接入 eCharts

    React Native 图表接入指南 概述 本文档详细介绍了在React Native项目中接入ECharts图表的完整步骤&#xff0c;包括依赖安装、组件配置、数据获取、图表渲染等各个环节。 目录 1. 环境准备2. 依赖安装3. 图表组件创建4. 数据获取Hook5. 图表配置6. 组件集成7. 国际化支持8…

    基于C#的OPCServer应用开发,引用WtOPCSvr.dll

    操作流程&#xff1a; 1.引入WtOPCSvr.dll文件 2.注册服务&#xff1a;使用UpdateRegistry方法注册&#xff0c;注意关闭应用时使用UnregisterServer取消注册。 3.初始化服务&#xff1a;使用InitWTOPCsvr初始化 4.使用CreateTag方法&#xff0c;创建标签 5.读写参数使用下面三…

    Java类加载器getResource行为简单分析

    今天尝试集成一个第三方SDK&#xff0c;在IDE里运行正常&#xff0c;放到服务器上却遇到了NPE&#xff0c;反编译一看&#xff0c;原来在这一行&#xff1a;String path Test.class.getClassLoader().getResource("").getPath(); // Test.class.getClassLoader().ge…

    【CodeTop】每日练习 2025.7.4

    Leetcode 1143. 最长公共子序列 动态规划解决&#xff0c;比较当前位置目标和实际字符串的字母&#xff0c;再根据不同情况计算接下来的情形。 class Solution {public int longestCommonSubsequence(String text1, String text2) {char[] t1 text1.toCharArray();char[] t2…

    ES6从入门到精通:Promise与异步

    Promise 基础概念Promise 是 JavaScript 中处理异步操作的一种对象&#xff0c;代表一个异步操作的最终完成或失败及其结果值。它有三种状态&#xff1a;Pending&#xff08;进行中&#xff09;、Fulfilled&#xff08;已成功&#xff09;、Rejected&#xff08;已失败&#xf…

    数据结构:二维数组(2D Arrays)

    目录 什么是二维数组&#xff1f; 二维数组的声明方式 方式 1&#xff1a;静态二维数组 方式 2&#xff1a;数组指针数组&#xff08;数组中存放的是指针&#xff09; 方式 3&#xff1a;双指针 二级堆分配 &#x1f4a1; 补充建议 如何用“第一性原理”去推导出 C 中…

    HAProxy 和 Nginx的区别

    HAProxy 和 Nginx 都是优秀的负载均衡工具&#xff0c;但它们在设计目标、适用场景和功能特性上有显著区别。以下是两者的详细对比&#xff1a;1. 核心定位特性HAProxyNginx主要角色专业的负载均衡器/代理Web 服务器 反向代理/负载均衡设计初衷高性能流量分发高并发 HTTP 服务…

    基于Java+SpringBoot的健身房管理系统

    源码编号&#xff1a;S586源码名称&#xff1a;基于SpringBoot的健身房管理系统用户类型&#xff1a;多角色&#xff0c;用户、教练、管理员数据库表数量&#xff1a;13 张表主要技术&#xff1a;Java、Vue、ElementUl 、SpringBoot、Maven运行环境&#xff1a;Windows/Mac、JD…