【icyle】Leetcode-cn:6. Z 字形变换

题目

将一个给定字符串 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

思路

观察字母下标规律法。

比如numRows是4,那么

  • 第一行是+6,+0交替,从a[0]开始
  • 第二行是+4,+2交替,从a[1]开始
  • 第三行是+2,+4交替,从a[2]开始
  • 第四行是+0,+6交替,从a[3]开始
0 1 2 3 4 5 6 7 8 9 10 11 12
P           I             N
A       L   S       I     G
Y   A       H   R
P           I
需要的头文件

string

代码
/*
 * @lc app=leetcode.cn id=6 lang=cpp
 *
 * [6] Z 字形变换
 */

// @lc code=start
#include <string>
using namespace std;
class Solution
{
public:
    string convert(string s, int numRows)
    {
        //排除简单情况
        if (numRows == 1)
        {
            return s;
        }

        //返回字符串
        string res;

        //index存放当前行计算间隔之后的下标
        //比如numRows是4,那么
        //第一行是+6,+0交替,从a[0]开始
        //第二行是+4,+2交替,从a[1]开始
        //第三行是+2,+4交替,从a[2]开始
        //第四行是+0,+6交替,从a[3]开始
        int index = 0;
        int slength = s.size();
        //间距
        int steps1 = 2 * numRows - 2;
        int steps2 = 0;

        for (int i = 0; i < numRows; i++)
        {
            index = i;
            //注意steps2和steps1的计算方式
            steps2 = 2 * i;
            while (index < slength)
            {
                res += s[index];
                //中间层是交替出现两个相加为const的数,想一想,8-6=2,8-2=6
                //我们不需要动被减数,将上一次的答案直接拿过来作减数
                //得到的结果刚好就是2,6交替出现
                steps2 = steps1 - steps2;
                index += (i == 0 || i == numRows - 1) ? steps1 : steps2;
            }
        }
        return res;
    }
};
// @lc code=end

时间复杂度和空间复杂度
  • 时间复杂度:遍历一次数组,所以为 O(n) ,其中n=len(s)。
  • 空间复杂度:定义了一个存放输出的返回数组,所以为 O(n) ,其中n=len(s)。

解答2

思路

按规律把“鸡蛋”放进对应的篮子,最后把篮子按顺序连起来。
以题目为例,numRows为3的Z形结构如下(吐槽出题人,这是N形,不是Z形)

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

假如用一个数组A存放以上字符,应该有

A[0]="PAHN"
A[1]="APLSIIG"
A[2]="YIR"

如果我们能确定存放规则,那么将A[0],A[1],A[2]连起来就可以得到答案。
存放规则只有一个:遍历到第一行和最后一行要上下反转
定义好当前行和当前方向这两个变量,问题就解决了。

需要的头文件

string

代码
/*
 * @lc app=leetcode.cn id=6 lang=cpp
 *
 * [6] Z 字形变换
 */

// @lc code=start
#include <string>
#include <vector>
using namespace std;
class Solution
{
public:
    string convert(string s, int numRows)
    {
        //排除简单情况
        if (numRows == 1)
        {
            return s;
        }

        //如果字符串比numRows还小,那么建立一个长度为s.size()的数组就可以了,多了是浪费空间
        vector<string> rows(min(numRows, int(s.size())));

        //返回数组
        string res;
        int slength = s.size();

        //定义当前行变量
        int rowIndex = 0;

        //反转标志,false为向下(+),true为向上(-)
        bool flag = false;

        for (int i = 0; i < slength; i++)
        {
            if (flag == false)
            {
                //注意这里的操作,反转方向之后这一步是会跳出到下一个i的
                //但是我们不能丢掉这一次的i,所以应该跳到合适的行的位置
                //把这次的“鸡蛋”i放进篮子里
                if (rowIndex == numRows)
                {
                    flag = true;
                    rowIndex -= 2;
                    rows[rowIndex--] += s[i];
                    continue;
                }
                rows[rowIndex] += s[i];
                rowIndex++;
            }
            else if (flag == true)
            {
                if (rowIndex == -1)
                {
                    flag = false;
                    rowIndex += 2;
                    rows[rowIndex++] += s[i];
                    continue;
                }
                rows[rowIndex] += s[i];
                rowIndex--;
            }
        }

        for (int j = 0; j < rows.size(); j++)
        {
            res += rows[j];
        }
        return res;
    }
};
// @lc code=end

时间复杂度和空间复杂度
  • 时间复杂度:遍历一次数组,所以为 O(n) ,其中n=len(s)。
  • 空间复杂度:定义了一个存放输出的返回数组,所以为 O(n) ,其中n=len(s)。

反思与总结

  1. 多思考解法1中如何实现变量的值“交替出现”。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值