leetcode 6

看完题目就蒙圈了,所以就直接看了别人的答案安静

几个答案看下来,基本上有这么三种思路

1.最清晰易懂的一种


string convert(string s, int numRows)
{
    if(s.size()<=1||numRows==1)
        return s;

    int len=s.size(),i,step=1,row=0;
    string *str=new string[numRows];

    for(i=0;i<len;i++)
    {
        str[row]+=s[i];

        if(row==0)
            step=1;
        if(row==numRows-1)
            step=-1;

        row+=step;
    }
    s.clear();
    for(i=0;i<numRows;i++)
        s.append(str[i]);

    delete[] str;

    return s;
}


这种解法可以说是非常巧妙了,我们来看看有哪些可以学习的地方。

首先对特殊情况的优先处理,能够节省不少时间,这个老生常谈了;然后这个算法核心思路是将zipzap之后的每一行都存在一个string类型数组的元素中,最后整合这些元素返回结果,很好理解,但是细节的处理非常高妙,主要是step和row这里的创新设计。每次row到达一个极端之后,step改变正负从而实现zigzag,真正是在模拟zigzag的过程,而不是单纯的找数学规律,这使得解法非常易懂。


而接下来的两种,就不是模拟zigzag了,而是找数学规律,所以比较费解一点。


class Solution {
public:
    string convert(string s, int nRows) {
        if(nRows == 1)  return s;
        int len = s.size(), k = 0, interval = (nRows<<1)-2;
        string res(len, ' ');
        for(int j = 0; j < len ; j += interval)//处理第一行
            res[k++] = s[j];
        for(int i = 1; i < nRows-1; i++)//处理中间行
        {
            int inter = (i<<1);
            for(int j = i; j < len; j += inter)
            {
                res[k++] = s[j];
                inter = interval - inter;
            }
        }
        for(int j = nRows-1; j < len ; j += interval)//处理最后一行
            res[k++] = s[j];
        return res;
    }
};

我们分析这个解法,他是直接从原来的s里按照题目要求顺序挑选出char并组成一个字符串返回的。首先也是对特殊情况处理,然后涉及到一个位运算的小知识,我们在文末会附上相关总结,现在我们只要知道<<是×的意思。这里interval就是每隔一个周期同一位置字母之间的距离(此处类比波形图,我不造怎么描述更清楚)对于第一行和最后一行,都是相差了一个周期,所以直接加上就好了;但是对于中间几行,引入了一个颇为抽象的变量inter,与interval一起实现上转折和下转折时计算间隔,也是非常巧妙的(我什么时候才能想出这么美的代码啊啊啊啊)

class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows == 1) {
            return s;
        }

        string result;
        size_t length = s.length();

        for (int i = 0; i < numRows; i++) {
            int long_step = 2 * numRows - 2 * (i + 1);
            int short_step = i * 2;
            int j = i;
            while (j < length) {
                if (long_step != 0) {
                    result.push_back(s[j]);
                    j += long_step;
                }
                if (j < length) {
                    if (short_step != 0) {
                        result.push_back(s[j]);
                        j += short_step;
                    }
                }
            }
        }

        return result;
    }
};


还有第三个······其实这个和第二个有异曲同工之妙啦,有木有发现,其实long_step就是上一个解法中interval-inter啦,而short—step就是inter~~~如果long_step!=0,说明不是最后一行,如果short_step!=0,说明不是第一行,也就是说,和上面一样,把首末两行和中间几行分开处理啦,但是这种解法很巧妙不用分情况讨论~可以说第三种是第二种的优化版本啦~再详细点说,如果是中间几行,也是在两种间隔计算方式之间循环,如果是首末,则long_step和short_step一样都是周期~因为只满足一个if条件,就会隔一个周期在result里塞进一个数。


嗯嗯,附上位运算·位运算~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值