题目:Z字形变换

第一次看到这道题,恍惚之间以为回到了儿童时期在做数学卷子。这tm就是个小学奥数题吧。

然后面对这个小学奥数题,我花费了一个下午(顺路刷完了毒奶粉账号的疲劳);

虽然花费的时间比较多但是提交之后发现又是一个超过百分之百的,感觉心情还不错。

代码如下:

static const auto io_speed_up = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return 0;
}();

class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows == 1)
            return s;
        int length   = s.size();
        int groupNum = numRows + numRows - 2;
        bool isShort = false;
        if (groupNum > length)
        {
            s =  s + string(groupNum - length, '0');
            length  = groupNum;
            isShort = true;
        }
        int quotient  = length / groupNum;
        int remainder = length % groupNum;
        vector<int> num(groupNum);
        vector<int> sum(numRows);
        int i = 0;
        int j = 0;
        for (i = 0; i < remainder; ++i)
            num[i] = 1;

        sum[1] = quotient + num[0];
        for (int i = 2; i < numRows; ++i)
        {
            j = i - 1;
            sum[i] = sum[j] + quotient + quotient + num[j] + num[groupNum - j];
        }

        i = 0;
        j = 0;
        int group = 0;
        int doubleRow = numRows - 1;
        string res(s);
        while (group < quotient)
        {
            res[sum[0]++] = s[i++];
            j = 1;
            while(j < doubleRow)
                res[sum[j++]++] = s[i++];
            res[sum[doubleRow]++] = s[i++];
            while(j > 1)
                res[sum[--j]++] = s[i++];
            ++group;
        }
        j = 0;
        int k = 0;
        while(j < doubleRow && k++ < remainder)
            res[sum[j++]++] = s[i++];
        if (i < length)
        {
            res[sum[doubleRow]++] = s[i++];
            ++k;
        }
        while(j > 1 && k++ < remainder)
            res[sum[--j]++] = s[i++];
        if (isShort)
        {
            char* temp = new char[length];
            for (i = 0, j = 0; i < length; ++i)
            {
                if(res[i] != '0')
                    temp[j++] = res[i];
            }
            temp[j] = '';
            res = string(temp);
        }
        return res;
    }
};

在这道题中,我把Z字型的一部分分为一组,即竖+斜等于一组,然后确定了两段每组会出现一个字符,然后中间的部分每组会出现两个字符。这里我们把输入为1的情况特殊处理,然后输入为2的情况,在代码中会跳过。接着因为这个方法处理字符最低为一组,所以我们碰到不足一组的在后面补‘0’补齐,然后把求出来的结果中‘0’字符去除。对于每一组,我们又可以分出两种情况,1是从上到下即N的竖线,2是从下到上即N的斜线,例如对于题目中所给的"PAYPALISHIRING",3这种情况我们可以分为

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

我把字符分为顶端,从上到下,底端,从下到上四种情况来处理,然后在处理完所有的组之后,我把不足一组的特殊处理。

字符的处理我是开辟了一个行数大小的数组,然后记录每个数组的起始地方的字符下标,然后每处理好一个字符把该行要处理的字符下标+1;

测完我的方法之后我去看了看之前排第一的方法,代码如下:

static auto static_lambda = [] () {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    return 0;
}();

class Solution {
public:
    string convert(string s, int numRows) {
        int length = s.length();
        if(length < numRows || numRows <= 1) return s;
        vector<string> r(numRows);
        int step = 1;
        int row = 0;
      
        for(int i = 0; i < length; i++)
        {
            if( row == numRows-1) step =-1;
            if(row == 0) step =1;
            
            r[row] += s[i];
            row += step;
        }
        
        string result;
        for (int i=0; i<numRows; i++)
            result += r[i];
        
         return result;
    }
};

他的代码很巧妙,把每一行设置成一个字符串,然后也是分组,每组两种情况。他设置碰到顶端,让下次累加字符串所在的数组是现在数组+1,如果碰到底端则是现在数组-1,到最后再把所有的字符串加起来。这种方法不需要考虑最后可能余下一部分不到一组的情况。

我觉得这个代码每次字符串拼接浪费了时间,如果把他拼接的部分改为:计算好字符串大小然后分配数组,在数组范围内操作,最后分配一个答案大小的字符串再循环赋值,这样的话速度会比我的代码还要快,并且更容易理解。

原文地址:https://www.cnblogs.com/change4587/p/9165184.html