【力扣】Z字形变换,模拟+直接构造

2024-02-06 10:44

本文主要是介绍【力扣】Z字形变换,模拟+直接构造,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Z字形变换原题地址

方法一:利用二维矩阵模拟

对于特殊情况,z字形变换后只有一行或只有一列,则变换后的字符串和原字符串相同。

对于一般情况,我们可以考虑按照题目要求,把字符串按照Z字形存储到二维数组中,再横向遍历所有有效字符

假设Z字形变换后的矩阵有r行,字符串的长度为n。

Z字形变换是按照周期t先向下,再向右上运动。一个周期t=r+(r-2)=r*2-2

其中r-2不包含两个红圈的位置。 一个周期t内的行数为r行,列数为1+(r-2)=r-1列,即最左边的一列以及中间的r-2列。矩阵的周期数为(n/t)向上取整,即(n+t-1)/t,加上的t-1是为了向上取整。矩阵的总列数为周期数*每个周期的列数,即c=(n+t-1)/t*(r-1)

那么,什么时候向下走,什么时候向右上方走呢?这要看当前处在周期的什么位置。假设当前遍历到下标为i的字符,如果imodt<r-1,即当前处在周期的前r-1个位置,就需要向下走,否则就要向右上方走

// 方法一:利用二维矩阵模拟
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或者只有一列if (r == 1 || r >= n)return s;// 周期t=r+r-2int t = r * 2 - 2;// 一共有 (n/t)向上取整 个周期// 即(n+t-1)/t个周期// 每个周期有1+r-2=r-1列int c = (n + t - 1) / t * (r - 1); // 列数// 构造矩阵,即r个string的数组,每个string的长度为cvector<string> mat(r, string(c, 0));int x = 0, y = 0; // 左上角for (int i = 0; i < n; ++i){mat[x][y] = s[i];// 周期前r-1次都是向下移动// 否则向右上方移动if (i % t < r - 1){++x;}else{--x;++y;}}string ans;// 拼接每行有效字符for (auto& row : mat){for (auto ch : row){if (ch)ans += ch;}}return ans;}
};

方法二:压缩矩阵空间

模拟时,可以不按照Z字形存储到矩阵中,而是根据当前字符在第几行,就存储在该行的最后一个位置,即尾插到当前行。这样的话可以节省矩阵的空间。

如果采用这种方案,就只需要考虑是向下走还是向上走。按照相同的思路,当imodt<r-1,即当前周期的前r-1个字符,需要向下走,反之就向上走。

// 方法二:压缩矩阵空间
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或只有一列if (r == 1 || r >= n)return s;vector<string> mat(r);// 周期t=r+r-2int t = r * 2 - 2;int x = 0; // 在第几个string后面添加字符for (int i = 0; i < n; ++i){mat[x] += s[i];// 每个周期前r-1次向下移动if (i % t < r - 1)++x;else--x;}string ans;// 拼接所有行for (auto& row : mat){ans += row;}return ans;}
};

方法三:方法二的另一种写法

在考虑是向下走还是向上走时,可以不用计算在当前周期的第几个位置,而是直接判断当前所处位置是否在最上面还是最下面。也就是说,如果当前在第x行,若x==1或者x==r-1,说明要转向本来是向下走就要转为向上走,本来是向上走就要转为向下走

我们可以定义一个flag,如果flag=1代表向下走,flag=-1代表向上走,每次只需要x+=flag就能求出新的所在行x了。如果要转向,只需执行flag=-flag

// 方法三:方法二的另一种写法,利用flag记录何时转向
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或只有一列if (r == 1 || r >= n)return s;vector<string> mat(r);int x = 0; // 在第几个string后面添加字符int flag = 1; // 行转向标志,1代表向下走,-1代表向上走for (int i = 0; i < n; ++i){mat[x] += s[i];x += flag;// 转向if (x == r - 1 || x == 0)flag = -flag;}string ans;// 拼接所有行for (auto& row : mat){ans += row;}return ans;}
};

方法四:直接构造

前三种方法都需要构造一个新的矩阵来模拟,我们可以考虑直接构造,也就是直接取出原字符串的字符来构造ans字符串。这就需要找出Z字形变换的规律,看图:

按照“Z字形”的顺序来看,就是0->1->2->3->...->t-2->t-1->t->t+1->t+2->...->2t-2->2t-1->2t->2t+1->2t+2->...

如果我们横着看呢? 我们用i来控制行,i从0递增到r-1。再用j控制列,j从0开始,每次递增t,也就是0,t,2t,3t,...。那么下图中,每个周期都是线+方框,线是i+j,框柱的是j+t-i

对于每一行,都有线,但是第0行和第r-1行没有方框内的元素,利用这点直接构造字符串即可。

// 方法四:直接构造
class Solution {
public:string convert(string s, int numRows) {int n = s.size();int r = numRows; // 行数// 只有一行或只有一列if (r == 1 || r >= n)return s;string ans;// 周期t=r+r-2int t = r * 2 - 2;for (int i = 0; i < r; ++i){for (int j = 0; j + i < n; j += t){// 当前周期第一个字符ans += s[j + i];// 若不是第一行和最后一行,还有第二个字符if (0 < i && i < r - 1 && j + t - i < n)ans += s[j + t - i];}}return ans;}
};

这篇关于【力扣】Z字形变换,模拟+直接构造的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/684065

相关文章

力扣SQL50 每位经理的下属员工数量 join

Problem: 1731. 每位经理的下属员工数量 👨‍🏫 参考题解 Code select m.Employee_id, m.name,count(*) reports_count,round(avg(e.age),0) average_agefrom Employees ejoin Employees mon e.reports_to = m.Employee_id

基于 Java 实现的智能客服聊天工具模拟场景

服务端代码 import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;public class Serv

将一维机械振动信号构造为训练集和测试集(Python)

从如下链接中下载轴承数据集。 https://www.sciencedirect.com/science/article/pii/S2352340918314124 import numpy as npimport scipy.io as sioimport matplotlib.pyplot as pltimport statistics as statsimport pandas

ccp之间是不可以直接进行+,-的,要用ccpSub和ccpAdd。

1.  http://www.cnblogs.com/buaashine/archive/2012/11/12/2765691.html  上面有好多的关于数学的方面的知识,cocos2dx可能会用到的 2.学到了   根据tilemap坐标得到层上物体的id int oneTiled=flagLayer->tileGIDt(tilePos);

把Tiled中做出的地图弄到项目中~~就是懒,为了以后直接复制写过来

1.现在.h中声明private: cocos2d::CCSprite* ninja; cocos2d::CCTMXTiledMap*  tileMap; 然后.cpp中加入tileMap = CCTMXTiledMap::create("MyTileMap.tmx"); CCTMXLayer* backLayer = tileMap->layerNamed("Tile L

直接得到Json串,转换为字典

0.新创建一个json文件,把json串拷贝到里面 1.先通过MainBundle找到资源对应的路径 2.将文件转换为NSData 3.通过NSJSonSerization得到字典 NSString*fileName=[[NSBundle mainBundle] pathForResource:@"myJson" ofType:@"json"];           NS

OSG数学基础:坐标系变换

三维实体对象需要经过一系列的坐标变换才能正确、真实地显示在屏幕上。在一个场景中,当读者对场景中的物体进行各种变换及相关操作时,坐标系变换是非常频繁的。坐标系变换通常包括:世界坐标系-物体坐标系变换、物体坐标系-世界坐标系变换和世界坐标系-屏幕坐标系变换(一个二维平面坐标系,即显示器平面,是非常标准的笛卡尔坐标系的第一象限区域)。 世界坐标系-物体坐标系变换 它描述的问题主要是关于物体本身的

PHP序列化用到的构造:__sleep() __wakeup()

串行化serialize可以把变量包括对象,转化成连续bytes数据. 你可以将串行化后的变量存在一个文件里或在网络上传输. 然后再反串行化还原为原来的数据. 你在反串行化类的对象之前定义的类,PHP可以成功地存储其对象的属性和方法. 有时你可能需要一个对象在反串行化后立即执行. 为了这样的目的,PHP会自动寻找__sleep和__wakeup方法.   当一个对象被串行化,PHP会

leetcode刷题(97)——106. 从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 中序遍历 inorder = [9,3,15,20,7]后序遍历 postorder = [9,15,7,20,3] 返回如下的二叉树: 3/ \9 20/ \15 7 看下后序和中序遍历的框架: void traverse(TreeNode root) {trave

leetcode刷题(97)——105. 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7 1.先回顾前序遍历和中序遍历的框架: void traverse(TreeNode root) {//