每日leetcode--(6) ZigZag Conversion

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

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

And then read line by line: "PAHNAPLSIIGYIR"

Write the code that will take a string and make this conversion given a number of rows:

string convert(string s, int numRows);

Example 1:

Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"

Example 2:

Input: s = "PAYPALISHIRING", numRows = 4
Output: "PINALSIGYAHRPI"
Explanation:

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

-----------------------------------------------------------------------------------------------------------------------

刚开始的时候想得比较直接:开一个1000*1000的二维数组,初始化成'\0',然后从左往右遍历给定的字符串,控制两个参数(i,j),让字符串中的每个字符按照zigzag的规则填入二维数组,最后逐行遍历该二维数组,将不是'\0'的字符拿出来,组成字符串作为结果返回。这么做超时了!

 

然后又开始想怎么能更快一点,后来发现其实,根本不需要构造二维数组,zigzag这一规则完全可以根据数学表达式递推出来。具体思路如下:

给定字符和对应下标如下所示

若行数==1:

就是一字排开,和原来的字符串一样,返回原来的字符串。

若行数==2:

对上述数组,遍历每一行(一共两行),

对每一行,下一列的字符下标和当前列的自负下表相差2*(numRows-2)+2。

举a为例子,a的下标是0,那么同一行下一列的字符d对应的下标就是0+2,这里的2就是通过2*(2-2)+2算得的。

若行数==3:

容易发现的是,首行(第0行)和末行(第2行),同行相邻列(比如a和e)的下标距离是个定值(a和e差4;c和g差4),这个距离可以直接由2*(numRows-2)+2算得(其实对任何情况,首行和末行,同行相邻列的距离都可以通过2*(numRows-2)+2算得)。

然后我们再看除首行和末行的那些行(这里就是第1行),

这里距离有两种,一种是b到d的距离(2*(numRows-3)+2算得),一种是b到f的距离(2*(numRows-3)+4算得),这样我们就可以通过b在字符串中的下标获得d和f在原字符串的下标了。之后再从f根据上述两种距离,算出h,j在原字符串中的下表,一直算下去,直到超出原字符串的长度,这一行就算完了。

之所以要弄两种距离,是应为当numRows超过3时,上述两种距离是不同的,具体如下:

若行数>3:

这种情况下,首行(第0行)和末行(第3行)依旧通过2*(numRows-2)+2算得。

对于第1行,b到f的距离(第一种距离)为2*(num-3)+2 = 4, b到h的距离(第二种距离)是2*(num-3)+4=6

对于第2行,c到e的距离(第一种距离)为2*(num-4)+2 = 2,c到i的距离(第二种距离)是2*(num-3)+4 = 6

所以可以发现,对中间的那些行(这里就是第1行和第2行)来说,第一种距离(b到f!=c到e)是随着行的不同而变化的,第二种(b到h==c到i)不随行的变化而变化。故这两种距离我们分开讨论。

综上,当给定行数numRows>3时:

对非首行和末行的情况:

第一种距离:2*(num-(i+2))+2  (其中i是行坐标)

第二种距离:2*(num-3)+4

对首行和末行的情况:

距离:2*(numRows-2)+2

 

贴上代码:

#include <iostream>
using namespace std;




class Solution {
public:
    string convert(string s, int numRows) {
        if(numRows==1)return s;
        string res = "";
        if(numRows==2)
        {
            int margine = 2;
            for(int i = 0;i<2;i++)
            {
                int temp = i;
                while(temp<s.size())
                {
                    res.append(1,s[temp]);
                    temp+=margine;
                }
            }
        }
        else if(numRows==3)
        {
            int margine1 = 4;
            int margine2 = 2;
            for(int i = 0;i<3;i++)
            {
                int temp = i;
                if(i==0||i==2)
                {
                    while(temp<s.size())
                    {
                        res.append(1,s[temp]);
                        temp+=margine1;
                    }
                }
                else
                {
                    while(temp<s.size())
                    {
                        res.append(1,s[temp]);
                        temp+=margine2;
                    }
                }
            }
        }
        else
        {
            int margine1 = 2*(numRows-2)+2;
            for(int i = 0;i<numRows;i++)
            {
                int temp = i;
                if(i==0||i==numRows-1)
                {
                    while(temp<s.size())
                    {
                        res.append(1,s[temp]);
                        temp+=margine1;
                    }
                }
                else
                {
                    int margine2 = 2*(numRows-(i+2))+2;
                    int margine3 = 2*(numRows-3)+4;
                    while(temp<s.size())
                    {
                        res.append(1,s[temp]);
                        int temp2 = temp+margine2;
                        if(temp2>=s.size())break;
                        res.append(1,s[temp2]);
                        temp2 = temp+margine3;
                        temp = temp2;
                    }
                }
            }
        }
        return res;
    }
};

应该还有更快的算法。待续。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值