• 每日一道 LeetCode (49):Z 字形变换


    每天 3 分钟,走上算法的逆袭之路。

    前文合集

    每日一道 LeetCode 前文合集

    代码仓库

    GitHub: https://github.com/meteor1993/LeetCode

    Gitee: https://gitee.com/inwsy/LeetCode

    题目:最长回文子串

    难度:中等

    题目来源:https://leetcode-cn.com/problems/zigzag-conversion/

    难度:中等

    将一个给定字符串根据给定的行数,以从上往下、从左到右进行 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
    

    解题方案一:按行排序

    这种题就是那种点型的一看不会做,一看答案感觉自己是怕不是个智障。

    最开始的时候想着使用纯暴力的方案去排那个字符串,但是这个字符串由于是 Z 字型的,那就需要用到二维数组,愣是没想通先竖着排完以后如何转向的问题。

    不得已之下去看了答案,看完以后恨不得抽自己俩大嘴巴子,直接用正负 1 来控制输出的转向就这么难想么?

    哎。。。感觉别人的脑子是个脑子,自己的脑子可能它只是挂了个名字。。。

    答案中并没有选择使用数组,而是使用了一个 List<StringBuilder> 的集合,也算是达到了一个二维数组的概念。

    public String convert(String s, int numRows) {
        // 极限值判断
        if (numRows == 1) return s;
        // 定义行
        List<StringBuilder> rows = new ArrayList<>();
        // 每一行都增加一个列
        for (int i = 0; i < Math.min(numRows, s.length()); i++)
            rows.add(new StringBuilder());
        // 定义当前行数
        int curRow = 0;
        // 定义是否转向
        boolean goingDown = false;
    
        for (char c : s.toCharArray()) {
            // 当前行添加一个字符
            rows.get(curRow).append(c);
            // 如果当前行是第一行或者是最后一行,转向标记位取反
            if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
            // 注意:这里计算了下一次循环的行数,并且完成了循环中转向
            curRow += goingDown ? 1 : -1;
        }
        // 定义输出
        StringBuilder ret = new StringBuilder();
        for (StringBuilder row : rows) ret.append(row);
        return ret.toString();
    }
    

    代码我就不解释了,每一行的注释都加好了,这个循环中转向的思路我以后绝对会记住的,简直是奇耻大辱。

    解题方案二:按行访问

    这个方案绝对是 NB 的大神拿个纸和笔坐在那活活推导出来的结果,就一个字,服!

    这个方案属于那种直接写结果的方案,直接按照逐行读取读取的顺序来输出整个字符串。

    这我还能说啥,知道了公式以后不就是照着公式写代码嘛,不知道公式就只能干瞪眼。

    其实我在刚看到这道题的时候就想,这个通项公式肯定存在,以我的能力估计是推导不出来,这个方案直接 pass 掉了。

    果然在答案中是能人辈出,直接给出通项公式:

    • 对于所有整数 k
    • 行 0 中的字符位于索引 k (2 * numRows - 2) 处。
    • 行 numRows - 1 中的字符位于索引 k (2 * numRows - 2) + numRows - 1 处。
    • 内部的行 i 中的字符位于索引 k (2 * numRows - 2) + i 以及 (k + 1)(2 * numRows - 2) - i 处。
    public String convert_1(String s, int numRows) {
        if (numRows == 1) return s;
        // 定义输出
        StringBuilder ret = new StringBuilder();
        int n = s.length();
        int cycleLen = 2 * numRows - 2;
    
        for (int i = 0; i < numRows; i++) {
            for (int j = 0; j + i < n; j += cycleLen) {
                ret.append(s.charAt(j + i));
                if (i != 0 && i != numRows - 1 && j + cycleLen - i < n)
                    ret.append(s.charAt(j + cycleLen - i));
            }
        }
    
        return ret.toString();
    }
    

    这个答案只能说仅供参考吧,完全不知道是怎么推导出来的。这道题主要是要记住第一个解题方案中的逆向迭代的方案,可以加一个转向标记位。

  • 相关阅读:
    Web负载均衡的几种实现方式
    Apache和Nginx的区别
    Nginx和Apache区别
    Git 使用中显示“Another git process seems to be running in this repository...”问题解决
    上传本地代码到gitHub过程详解
    MySQL数据库中varchar与char类型的区别
    正则表达式中/i,/g,/ig,/gi,/m的区别和含义
    内行看门道:看似“佛系”的《QQ炫舞手游》,背后的音频技术一点都不简单
    惧怕羊毛党?腾讯云为你保驾护航
    教你1天搭建自己的“微视”
  • 原文地址:https://www.cnblogs.com/babycomeon/p/13710174.html
Copyright © 2020-2023  润新知