【力扣刷题】【1-50】6. Z 字形变换

本文详细介绍了Z字形变换的两种方法,包括模拟遍历和对应规律。通过分析周期规律,提出了解决问题的具体步骤,并提供了C++代码实现。内容涉及字符串处理、矩阵变换和算法设计,适合对算法和数据结构感兴趣的读者阅读。
摘要由CSDN通过智能技术生成

6. Z 字形变换

1.模拟遍历

  • 模拟题目中给出的Z字转换规则,直接得出结果;

  • 事先计算清楚结果有几行几列,方便直接使用下标遍历:

    行数:即是题目中给出的numRows;

    列数:可以将Z字转换分成一个个操作相同的周期。这里注意,如果将一个完整的“Z”视为一个周期,分析起来比较麻烦,真正的周期是“Z”少了下面一个横的形

    不难看出,每个周期内的元素C=numRows(直线部分)+numRows-2(斜线部分);

    因此周期数T=s.size()/周期内元素个数C;

    每个周期有numRows-1列;

    因此*列数为(numRows-1)s.size()/T

    以下图以numRows=4为例:

    [外链图片转存中...(img-Etl43JO771f06cf99056ccf22576)

  • vector的构造:

    vector的构造可以不规定大小,随着插入动态的增长:vector<string>Z_result;

    也可以规定初始大小,可以按照下标直接访问:vector<string>Z_result(n);

    规定初始大小基础上,第二个参数还能初始化值,vector<string> Z_result(numRows, string(numCols, 0));

    在这里填入了numRows个,numCols长度,初始值全是0的string,便于我们后面可以直接用二维坐标操作。

    class Solution {
    public:
        string convert(string s, int numRows) {
            string result;
            int n=s.size();
            if(numRows==1){//这种情况会展开成一行,直接返回,否则下面num_a_cycle计算会出现除0错误
                return s;
            }
            int num_a_cycle=numRows+numRows-2;//每个周期内的节点数
            int cycles=n/num_a_cycle+1;//总共有几个周期
            int numCols=cycles*(numRows-1);//每一个周期有numRows-1列
            vector<string> Z_result(numRows, string(numCols, 0));
            int ind_X=0,ind_Y=0;//ind_Y代表纵向的坐标,ind_X代表横向的坐标
            for(int i=0;i<n;i++){
                Z_result[ind_Y][ind_X]=s[i];
                if(i%num_a_cycle<numRows-1){//这里属于Z字型的横部分
                    ind_Y++;
                }else{//这里属于Z字型的斜部分
                    ind_X++;
                    ind_Y--;
                }
            }
            // 可以用这部分代码输出Z字转换后的结果查看
            // for(int i=0;i<numRows;i++){
            //     for(int j=0;j<numCols;j++){
            //         cout<<Z_result[i][j];
            //     }
            //     cout<<endl;
            // }
            for(int i=0;i<numRows;i++){
                for(int j=0;j<numCols;j++){
                    if(Z_result[i][j]){
                        result+=Z_result[i][j];
                    }
                }
            }
            return result;
        }
    };
    

2.对应规律

  • 根据上面周期规律的分析,其实我们可以分析出Z转换后的矩阵和S中下标的对应规律;

  • 不难发现,每个周期第一行和最后一行有一个元素,其他行都是两个;

  • 假设当前在第T个周期,每个周期有元素C,这两个数的计算方式在方法1中。

    对于第一行(我们的row从0开始编号)来说,下标都是每个周期的第一个元素,对应的下标就是0+T*C

    (我们不妨将当前在第几个周期T也从0开始编号);

    那么第二行呢?第二行可能会有两个元素,我们先不讨论第二个元素,只看第一个:

    下标都是每个周期的第二个元素,对应的下标是1+T*C

    同理可以推到第numRows行,对应的下标是 (numRows-1)+T*C

  • 我们再看其他行的第二个位置,其实可以根据改行第一个元素推理:

    2行:第一个位置,是该周期正数第2个元素,第二个位置,是该周期倒数第1个元素;

    3行:第一个位置,是该周期正数第3个元素,第二个位置,是该周期倒数第2个元素;

    i行:第一个位置,是该周期正数第i个元素,第二个位置,是该周期倒数第i-1个元素;

    其实第二个位置和行数存在一定关系的,下标是T*C-i;

    下图将元素序号和周期内元素个数进行了取余操作,便于理解周期性质。
    在这里插入图片描述

    class Solution {
    public:
        string convert(string s, int numRows) {
            string result;
            int n=s.size();
            if(numRows==1){//这种情况会展开成一行,直接返回,否则下面num_a_cycle计算会出现除0错误
                return s;
            }
            int num_a_cycle=numRows+numRows-2;//每个周期内的节点数
            int cycles=n/num_a_cycle+1;//总共有几个周期
            int numCols=cycles*(numRows-1);//每一个周期有numRows-1列
            for(int i=0;i<numRows;i++){//i代表行数,进行遍历
                int ind=i;
                if(i==0||i==numRows-1){//第一行和最后一行,每周期只有一个元素,在s中的坐标是行数的整数倍数
                    while(ind<n){
                        result+=s[ind];
                        ind+=num_a_cycle;
                    }
                }else{//其他行一次处理两个元素
                int T_cnt=1;
                    while(ind<n){
                        result+=s[ind];//第一个元素仍然是行数的整数倍数
                        int pos2=num_a_cycle*T_cnt-i;
                        if(pos2<n){//第二个元素需要判断是否超界
                            result+=s[pos2];
                        }
                        ind+=num_a_cycle;
                        T_cnt++;
                    }
                }
            }
            return result;
        }
    };
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值