力扣算法 6.N 字形变换

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

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

力扣算法 6.N 字形变换_第1张图片

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

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

string convert(string s, int numRows);

力扣算法 6.N 字形变换_第2张图片
力扣算法 6.N 字形变换_第3张图片

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

设n为字符串s的长度 ,r=numRows。对于r=1(只有一行)或者r>=n(只有一列的情况),答案与s相同,我们可以直接返回s。对于其余的情况,考虑创建一个二维矩阵,然后在矩阵上按Z字形填写字符串s,最后逐行扫描矩阵中的非空字符,组成答案。

根据题意,当我们在矩阵上填写字符时,会向下填写r个字符,然后向右上继续填写r-2个字符,最后回到第一行,因此Z字形变换的周期t=r+r-2=2r-2,每个周期会占用矩阵上的1+r-2=r-1列

因此我们有[n/t]个周期(最后一个周期视作完整周期),乘上每个周期的列数,得到矩阵的列数c=[n/t]*(r-1)。

创建一个r行c列的矩阵,然后遍历字符串s并给Z字形填写。具体来说,设当前填写的位置是(x,y)即矩阵的x行y列。初始(x,y)=(0,0),也就是矩阵的左上角。如果当前字符下标i满足i mod t

填写完成后,逐行扫描矩阵中的非空字符,组成答案

class Solution {
public:
    string convert(string s, int numRows) {
        int n=s.length(),r=numRows;//获取字符串长度以及需要分的行数
        if(r==1||r>=n)//直接返回s
        {
            return s;
        }
        int t =r*2-2;//t 是之字形周期(等于 2r - 2)
        int c =(n+t-1)/t*(r-1);//字符串所需的列数
        // (n + t - 1) / t 计算可放入字符串 s 中的完整之字形循环数,四舍五入为最接近的整数。这相当于将 s 中的字符总数除以每个完整之字形循环中的字符数,然后将任何小数结果四舍五入。
        vector<string> mat(r,string(c,0));
        //vector(r, string(c, 0)) 创建一个 r 行和 c 列的二维向量,其中每个元素都是一个长度为 c 的字符串,用字符 0 填充。这是使用向量构造函数完成的两个参数:第一个参数指定要创建的元素数,第二个参数指定初始化每个元素的值。
        for (int i=0,x=0,y=0;i<n;++i)
        {
            mat[x][y]=s[i];
            if(i%t<r-1)
            {
                ++x;//向下移动
            }else{
                --x;
                ++y;//向右上移动
            }
        }
        string ans;
        for(auto &row :mat)//遍历行
        {
            for(char ch :row)//遍历行内字符
            {
                if(ch)
                {
                    ans+=ch;
                }
            }
        }
        return ans;
    }
};

其它方法待更新

你可能感兴趣的:(力扣算法题,算法,leetcode,矩阵)