LeetCode琅琊榜第十六层-Z字型变换(直接构造法 + 周期性算法)

LeetCode6.Z字形变换

难度:中等

往期力扣博主空间

题目链接 


目录

官方解法1-构造Z字型数组模拟

案例分析

规律探索

原因:

代码实现

代码分析:

问题

官方解法二-压缩上述二维数组

思路分析

代码实现

代码分析

问题

官方解法三-直接构造法

算法思想

代码实现

代码分析

结论 


官方解法1-构造Z字型数组模拟

案例分析

案例一:

s = "PAYPALISHIRING", numRows = 3,当该案例构造成数组时,得到以下的图形

案例二:

s = "PAYPALISHIRING", numRows = 4当该案例构造成数组时,得到以下的图形

规律探索

 

  • 1.通过上面两个案例可得,我们可以将一列和一条斜线做作为一个周期t, t = r + r - -2 = 2r - 2
  • 2.通过观察,一个周期占用了r - 1
  • 3.假设,一共有n个元素,那么,n个元素一共有n / t 个周期,一共占用 c = n / t * (r - 1)列
  • 但是,由于可能最后几个元素不满一个周期,上面的等式明显是有问题的,只会取整,即会漏掉不满一个周期的那几个元素,要想解决这个问题,需将等式转换成 c  = (n + t - 1)/t * (r - 1)

原因:

  • 如果有这么一个场景,其一列能放六个元素,问13个元素需要放几列
  • 如果按照上面的思想去做这道题,t = 6,n = 13, c = n / t = 2,结果为2
  • 但是,显然,我们需要三行才可以承载所有的元素,所以,我们需要加上5即 18 / 6 = 3,就是三行
  • 同理上面

代码实现

class Solution {
    public String convert(String s, int numRows) {
        var r = numRows;
        var t = 2 * r - 2;
        var n = s.length();
        if (r >= n || r == 1) {
            return s;
        }
        var c = (n + t - 1)/t * (r - 1);
        var strBul = new StringBuilder();
        var matrix = new char[r][c];
        for (int i = 0,x = 0,y = 0; i < n; i++) {
            matrix[x][y] = s.charAt(i);
            if (i % t < r - 1) {
                x++;
            }else {
                x--;
                y++;
            }
        }
        for (int i = 0; i < r; i++) {
            for (int j = 0; j < c; j++) {
                if (matrix[i][j] != 0) {
                    strBul.append(matrix[i][j]);
                }
            }
        }
        return strBul.toString();
    }
}

代码分析:

  • 1.第一个判断
    • 1.1r >= n时,就是所需要的行大于等于元素个数n,就是一整列的情况,不需要构造Z,直接返回
    • 1.2r == 1时,就是所需要的行等于1,就是一整行的情况,不需要构造Z,直接返回
  • 2.声明matrix二维数组用于构造Z字形与strBul拼接字符串
  • 3.for循环
    • 3.1变量的定义与初始化
      • 3.1.1 'i'用于遍历字符串,表示第i + 1个元素的下标,并初始化为0
      • 3.1.2 'x,y'分别表示二维数组matrix中的行与列,并初始化为0(我们从最左上角开始构造Z)
    • 3.2追加
    • 3.3if else详解
  • 4.最后将横向遍历二维数组,不是0的都拼接上去即可

问题

  • 这种解法会产生大量的冗余空间,这些冗余空间使得代码效率变低

官方解法二-压缩上述二维数组

思路分析

  • 我们不直接构造上述的二维数组,转而我们构造多个StringBuilder去完成上述的代码

代码实现

class Solution {
    public String convert(String s, int numRows) {
        var res = new StringBuilder();
        var r = numRows;
        var t = 2 * r - 2;
        var tBul = new StringBuilder[r];
        var n = s.length();
        for (int i = 0; i < r; i++) {
            tBul[i] = new StringBuilder();
        }        
        if (r >= n || r == 1) {
            return s;
        }
        for (int i = 0,x = 0; i < n; i++) {
            tBul[x].append(s.charAt(i));
            if (i % t < r - 1) {
                x++;
            }else {
                x--;
            }
        }
        for (var item : tBul) {
            res.append(item);
        }
        return res.toString();
    }
}

代码分析

  • 1.注意,在构造StringBuilder数组的时候不要用Arrays工具类里面的fill方法,因为这样会导致所有的下标都指向同一个StringBuilder对象
  • 2.for循环
    • 2.1因为每一个都是StringBuilder,所以y的创建就没有必要了
    • 2.2根据方法一的思想,让x移动即可,注意,如果拼接,它相当于y++,是等效的
  • 3.将所有的StringBuilder拼接起来即可

问题

  • 还是用到了额外的空间,能否直接拼接呢?

官方解法三-直接构造法

算法思想

  • 根据方法一所给的图像,利用里面隐藏的元素下标直接拼接,无需构造

代码实现

class Solution {
    public String convert(String s, int numRows) {
        var res = new StringBuilder();
        var r = numRows;
        var t = 2 * r - 2;
        var n = s.length();
        if (r == 1 || r >= n) {
            return s;
        }
        for (int i = 0; i < r; i++) {
            for (int j = 0; j + i < n; j += t) {
                res.append(s.charAt(j + i));
                if (i < r - 1 && i > 0 && j + t - i < n) {
                    res.append(s.charAt(j + t - i));
                }
            }
        }
        return res.toString();
    }
}

代码分析


结论 

        这道算法题更多的是推导,也没有说具体的用什么有名字的算法,刷刷刷,刷着刷着就会了,我来总结一下的几点

        1.方法一中,[t,r,c,n]概念的深化理解

                2.方法一的代码实现

                        3.方法三的代码实现

        最后,当我们发现某个算法示例呈周期性变化的时候,都可以借鉴此算法

猜你喜欢

转载自blog.csdn.net/JOElib/article/details/124753771