N 字形变换

Posted crazypig

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了N 字形变换相关的知识,希望对你有一定的参考价值。

题目描述

难度中等

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

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

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

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:

输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"

示例 2:

输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I

示例 3:

输入:s = "A", numRows = 1
输出:"A"

提示:

  • 1 <= s.length <= 1000
  • s 由英文字母(小写和大写)、\',\'\'.\' 组成
  • 1 <= numRows <= 1000

解题步骤

时间复杂度和空间复杂度都是\\(O(n)\\)

class Solution:
    def convert(self, s: str, numRows: int) -> str:
        # 定义两个步伐长度step1 = 2 * i,step2 = 2 * (numRows-1) - step1
        # 通过观察发现规律,第i行在第i个字符的前提下以step2, step1的步伐交替前进
        # 比如示例1的第一行在P的情况下以4,0,第二行在A的情况下以2,2,第三行在Y的情况下以0,4交替前进
        # 其中当步伐为0时不用记录
        n = len(s)
        if numRows == 1:
            return s
        res = [None] * n
        k = 0
        for i in range(numRows):
            step1 = 2 * i
            step2 = 2 * (numRows-1) - step1
            j = i
            flag = 1
            while j < n:
                if flag == 1:
                    if step2 != 0:
                        res[k] = s[j]
                        k += 1
                    j = j + step2
                else:
                    if step1 != 0:
                        res[k] = s[j]
                        k += 1
                    j = j + step1
                flag = -flag
        return "".join(res)

How to calculate the z-graph transformation problem with the time complexity of o(n)(Z字形变换问题)

Question

        The string "PAYPALISHIRIN"  is written in a zigzag parttern on a given number of rows like this:         

 P     A     H     N
 A  P  L  S  I  I  G
 Y     I     R

        And then read line by line "PAHNAPLSIIGYIR",  please finish it with the time complexity of o(n).

Implementation approach

        We can use Matrix to put these data, then iterator in order.

How to determine the size of Matrix?

        Let's image that the parttern of these data, if we can determine the column of Matix ,the shape of matrix is determined.

        Principle:

        We can substract rows by rows-2 is equivalent to removing columns,then removing slashed,col+1,and the resulting value is the col of Matrix.

 /**
     * 根据字符串的长度和指定的行数计算会展示的列数。
     * Calculates the number of columns to be displayed based on the length of the string and specified number of rows.
     * 原理: 每减一个rows然后再减一次rows-2, 相当于先去除掉列,然后再去除掉斜线,col+1, 最终得到的值即为Matrix的col
     * Principle:Subtracting rows by rows-2 is equivalent to removing columns, then removing slashes,col+1, and the resulting value is the col of Matrix
     * @param length
     * @param rows
     * @return
     */
    private static int calculateColByLengthAndRows(int length, int rows) {
        int col = 0;
        while (length > 0) {
            if (col % 2 == 0) {
                length -= rows;
            } else {
                length -= rows - 2;
            }
            col++;
        }
        return col;
    }

         warning:  the method identifies a problem with the number of columns  and  temporarily sets the number of columns to the length of string.

How to put values in matrix and take  them out?

     *1. put values

        This step is the central to implementing the algorithm.We are going to put the values in matrix according to the Z trajectory.

        Each time you put a value, determine whether it is in the column or on the slash.

        If the value is in the column, then the 'i' + 1 of the value's coordinate is prepared for the next initialization of the matrix coordinates. if +1 exceeds the maximum number of rows, then the coordinates is moved to the uper right corner, j+1, i-1.

        If the value is on the slash,it is determined whether the value has a value in the lower or upper left corner, and if the lower left corner has a value, the upper right corner of the value will be the coordinate where the value is the next stored in the matrix. If the upper left corner has a value, the lower right corner of that value will be the next coordinate that value is stored in the matrix.

   private static String TraverseZigZagByLine(String s, int rows) {
        int length = s.length();
        if (rows == 1) {
            return s;
        }
        // calculate the number of columns according to the length of s;
//        int col = calculateColByLengthAndRows(length, rows);
        int col = length;
        String[][] arr = new String[rows][col];
        traverseTwoDimensionalArray(arr);
        int index = 0;
        // init matrix
        int i = 0, j = 0;
        // 时间复杂度o(n)
        while (index < length) {
            // calculate the position of each index in the matrix.
            boolean diagonalLine = initMatrix(arr, rows, s.charAt(index) + "", i, j);
            if (diagonalLine) {
                // 如果在斜线上,判断左上角或者左下角是否有值,如果任意一个有值,那么在相反方向的下一个位置赋值
                boolean empty = true;
                if (arr[i + 1][j - 1] != null) {
                    // 左下角有值
                    i--;
                    j++;
                    empty = false;
                }
                if (empty && arr[i - 1][j - 1] != null) {
                    // 左上角有值
                    i++;
                    j++;

                }
            } else {
                // 如果在直线上,那么向下+1,如果超过,那么就向右上角移动
                if (i + 1 == rows) {
                    i--;
                    j++;
                } else {
                    i++;
                }
            }
            index++;
        }
        return traverseTwoDimensionalArray(arr);
    }

        It should be noted that:   the bottom left corner and the top left corner can only choose one.

        2. take values

        We can take value by dual for loop, and then put it into StringBuilder.

  private static String traverseTwoDimensionalArray(String[][] array) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                if (array[i][j] != null) {
                    sb.append(array[i][j]);
                }
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
        return sb.toString();
    }

Complete code

package leetcode100;

/**
 * @author bingbing
 * @date 2021/8/12 0012 11:05
 * Z字形问题
 * ZigZag Problem
 * P     A     H     N
 * A  P  L  S  I  I  G
 * Y     I     R
 * 最后的结果可以根据行数来进行输出
 * The final result is printed base on the number of rows.
 */
public class ZigZagProblem {


    public static void main(String[] args) {
        String s = "PAYPALISHIRIN";
        String result = TraverseZigZagByLine(s, 5);
        System.out.println(result);
    }

    /**
     * 借助二维数组,二维数组的行数按照num来初始化
     * init two-dimensional array
     *
     * @param s
     * @param rows
     * @return
     */
    private static String TraverseZigZagByLine(String s, int rows) {
        int length = s.length();
        if (rows == 1) {
            return s;
        }
        // calculate the number of columns according to the length of s;
//        int col = calculateColByLengthAndRows(length, rows);
        int col = length;
        String[][] arr = new String[rows][col];
        traverseTwoDimensionalArray(arr);
        int index = 0;
        // init matrix
        int i = 0, j = 0;
        // 时间复杂度o(n)
        while (index < length) {
            // calculate the position of each index in the matrix.
            boolean diagonalLine = initMatrix(arr, rows, s.charAt(index) + "", i, j);
            if (diagonalLine) {
                // 如果在斜线上,判断左上角或者左下角是否有值,如果任意一个有值,那么在相反方向的下一个位置赋值
                boolean empty = true;
                if (arr[i + 1][j - 1] != null) {
                    // 左下角有值
                    i--;
                    j++;
                    empty = false;
                }
                if (empty && arr[i - 1][j - 1] != null) {
                    // 左上角有值
                    i++;
                    j++;

                }
            } else {
                // 如果在直线上,那么向下+1,如果超过,那么就向右上角移动
                if (i + 1 == rows) {
                    i--;
                    j++;
                } else {
                    i++;
                }
            }
            index++;
        }
        return traverseTwoDimensionalArray(arr);
    }


    /**
     * @param arr
     * @param rows
     * @param value
     * @param i
     * @param j
     * @return
     */
    private static boolean initMatrix(String[][] arr, int rows, String value, int i, int j) {
        // 判断横坐标是否满足条件
        arr[i][j] = value;
        return j % (rows - 1) != 0;
    }

//    /**
//     * 根据字符串的长度和指定的行数计算会展示的列数。
//     * Calculates the number of columns to be displayed based on the length of the string and specified number of rows.
//     * 原理: 每减一个rows然后再减一次rows-2, 相当于先去除掉列,然后再去除掉斜线,col+1, 最终得到的值即为Matrix的col
//     * Principle:Subtracting rows by rows-2 is equivalent to removing columns, then removing slashes,col+1, and the resulting value is the col of Matrix
//     *
//     * @param length
//     * @param rows
//     * @return
//     */
//    private static int calculateColByLengthAndRows(int length, int rows) {
//        int col = 0;
//        while (length > 0) {
//            if (col % 2 == 0) {
//                length -= rows;
//            } else {
//                length -= rows - 2;
//            }
//            col++;
//
//        }
//        return col;
//    }


    private static String traverseTwoDimensionalArray(String[][] array) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                if (array[i][j] != null) {
                    sb.append(array[i][j]);
                }
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
        return sb.toString();
    }
}

Input value: "PAYPALISHIRIN" , 5

print result:

         From what has been discussed, We complete the arithmetic  with the time complexity of O(n), and the space complexity is O(n);

以上是关于N 字形变换的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 6Z 字形变换

6. Z 字形变换

Leet Code 6.Z字形变换

How to calculate the z-graph transformation problem with the time complexity of o(n)(Z字形变换问题)

LeetCode 6[找规律] Z字形变换 HERODING的LeetCode之路

N字形变化 flag标签转换方向