【每日刷题】Z 字形变换

题目地址

https://leetcode-cn.com/problems/zigzag-conversion/

题目描述:Z 字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:

L   C   I   R
E T O E S I I G
E   D   H   N

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。

再比如输入字符串为 “LEETCODEISHIRING” 行数为 4 时,排列如下:

L     D     R
E   O E   I I
E C   I H   N
T     S     G

请你实现这个将字符串进行指定行数变换的函数:string convert(string s, int numRows);

解答

这个问题并不复杂。

方法一:按行排序

首先给出一个较为直观的算法,利用辅助空间(二维数组),使用向上/向下标记来选定方向,构造 Z 字形字符串。

代码:

class Solution {
public:
    string convert(string s, int numRows) {
        // 当 numRows == 1 时, 返回原字符串
        if( numRows == 1)
            return s;
        
        //当numRows == 2时, 返回原数组中字符交替
        if( numRows == 2){
            string res;
            for( int i = 0; i < s.size(); i+=2)
                res +=s[i];
            for( int i = 1; i < s.size(); i+=2)
                res += s[i];
            return res;
        }
        
        // 以下情况适合于 numRows >= 3 时,此时存在一个 Z 型
        //为了方便,创建足够大的辅助空间
        vector< vector< char>> record( numRows, vector<char>( s.size()));
        
        int down = 1, count = 0;
        int temp = numRows;
        for( int i = 0; i < s.size(); i++)
            if( down){
                record[ numRows - temp][count] = s[i];
                temp--;
                if( !temp)
                    temp = numRows - 2, down = 0, count++;
            }
            else{
                record[ temp][count++] = s[i];
                temp--;
                if( !temp)
                    temp = numRows, down = 1;
            }
        
        string res;
        for( int i = 0; i < numRows; i++)
            for( int j = 0; j < s.size(); j++)
                if( record[i][j])
                    res += record[i][j];
                    
        return res;
        
    }
};
//时间复杂度为O( numRows * s.size())
// 可以通过优化空间,将算法运行时间优化到到 O(n)

方法二:按行访问。(依据下标的规律)

首先读取第 0 行的字符,之后读取第 1 行, 第 2 行,…,第 numRows - 1 行的字符。

对于所有的整数 k:

  1. 第 0 行的字符位于索引 k( 2 * numRows - 2) 处;
  2. 第 numRows - 1 行中的字符位于索引 k * (2 * numRows - 2) + numRows - 1 处;
  3. 内部第 i 行的字符位于索引 k(2numRows - 2) + i 和 (k+1)( 2numRows) - i处。
class Solution {
public:
    string convert(string s, int numRows) {

        if (numRows == 1) return s;

        string res;
        int cycleLen = 2 * numRows - 2;

        for (int i = 0; i < numRows; i++) { //
            for (int j = 0; j + i < s.size(); j += cycleLen) {
                res += s[j + i];
                if (i != 0 && i != numRows - 1 && j + cycleLen - i < s.size())
                    res += s[j + cycleLen - i];
            }
        }
        return res;
    }
};
// 改算法运行时间为O(n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值