zoukankan      html  css  js  c++  java
  • LeetCode(C++)刷题计划:6-Z字形变换

    6-Z字形变换

    @Author:CSU张扬
    @Email:csuzhangyang@gmail.com or csuzhangyang@qq.com

    1. 题目

    将一个给定字符串根据给定的行数,以从上往下、从左到右进行Z字形排列。
    比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:

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

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

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

    示例 1:
    输入: s = "LEETCODEISHIRING", numRows = 3
    输出: "LCIRETOESIIGEDHN"
    
    示例 2:
    输入: s = "LEETCODEISHIRING", numRows = 4
    输出: "LDREOEIIECIHNTSG"
    解释:
    L     D     R
    E   O E   I I
    E C   I H   N
    T     S     G
    

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/zigzag-conversion

    2. 解法

    2.1 解法一

    按每行从左到右依次输出。
    以示例2为例,

    L     D      R
    E   O E    I I
    E C   I  H   N
    T     S      G
    对应的下标如下:
    0     6      12
    1   5 7   11 13
    2 4   8 10   14
    3     9      15
    

    我们的任务是找出每一行的下标。

    1. 对于第一行和最后一行来说,它只有3个数,而其他行是它的二倍,有6个数。
    2. 我们以下标0-5为第一组,6-11为第二组,以此类推,每6个数一组,不足6个数的也算作一组。
    3. 6是怎么求的呢?k = 2 * (numRows - 1) = 2*(4-1) = 6
    4. 一共有多少组呢?loopNum = (n + k - 1) / k;(n为s的长度),注意:不足k个的也算作一组。
    5. 对于第一行和最后一行来说,初值为i(start1 = i),我们只需要每次循环加上k即可。
    6. 对于其他行,我们每组有两个数。前一个数和步骤5中一样,初值为i(start1 = i);第二个数的初值是关键,start2 = start1 + (numRows-(i+1))*2;每次循环都加上k即可,循环总次数为numRows。

    执行用时 :8 ms, 在所有 cpp 提交中击败了97.82%的用户
    内存消耗 :10.3 MB, 在所有 cpp 提交中击败了88.53%的用户

    class Solution {
    public:
        string convert(string s, int numRows) {
            int n = s.size();
            if (numRows == 1)
                return s;
            int k = 2 * (numRows - 1);
            string str = "";
            int loopNum = (n + k - 1) / k;
            for (auto i = 0; i < numRows; ++ i) {
                int start1 = i;
                int start2 = 0;
                if (i != 0 && i != (numRows -1))
                    start2 = start1 + (numRows-(i+1))*2;
                for (auto j = 0; j < loopNum; ++ j) {
                    if (start1 < n) {
                        str += s[start1];
                        start1 += k;
                    }
                    if (i != 0 && i != (numRows -1)) {
                        if (start2 < n) {
                            str += s[start2];
                            start2 += k;
                        }
                    }
                    if (start1 >= n && start2 >= n)
                        break;
                }
            }
            return str;
        }
    };
    

    2.2 解法二

    参考:麓山南路飞行员

    主要思想就是:一共有numRows行,找出每个字符所在的行数,依次添加到该行。
    关键代码int row = i % k < numRows ? i % k : k - i % k;

    以示例2为例,

    L     D      R
    E   O E    I I
    E C   I  H   N
    T     S      G
    对应的下标如下:    行数:
    0     6      12     0
    1   5 7   11 13     1
    2 4   8 10   14     2
    3     9      15     3
    

    易知k = 6, numsRows = 4,我们以下标0-5为例。第一种情况是下标0-3,第二种情况是下标4-5,这两种情况区分的标志是i % k < numRows

    很容易知道第一种情况的行数为i % k;第二种情况,对于5来说,row = 1 = 6 - 5;对于11来说,row = 1 = 6 - 11...,11怎么才能变成5呢,当然是对6取余啦。所以第二种情况行数为k - i % k

    执行用时 :20 ms, 在所有 cpp 提交中击败了58.47%的用户
    内存消耗 :12.7 MB, 在所有 cpp 提交中击败了78.71%的用户

    class Solution {
    public:
        string convert(string s, int numRows) {
            if (numRows == 1)
                return s;
            int n = s.size();
            int k = 2 * (numRows - 1);
            string str;
            vector<string> res(numRows);
            for (auto i = 0; i < n; ++ i) {
                int row = i % k < numRows ? i % k : k - i % k;
                res[row] += s[i];
            }
            for (auto i : res)
                str += i;
            return str;
        }
    };
    
  • 相关阅读:
    OI回忆录
    【CSP2019】题解合集
    微电影《Junior·BQB》——剧本
    【UOJ139】【UER #4】被删除的黑白树
    NOIWC2019 冬眠记
    THUWC2019 划水记
    【XSY3413】Lambda
    【BZOJ3065】带插入区间k小值
    【BZOJ3600】没有人的算术
    【BZOJ4864】【BJWC2017】神秘物质
  • 原文地址:https://www.cnblogs.com/MagicConch/p/12179164.html
Copyright © 2011-2022 走看看