面试经典算法150题系列-Z字形变换

z字形变换

将一个给定字符串 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"

实现思路:

这题先说一下题目,它是选取字符串的每个字母进行排列,按照限定行数,先从上往下排列,然后再从左往右进行排列,最终排出的形状如同几个逆时针旋转90度的 "Z"字形状。

实现思路一:暴力求解

我们就使用二维数组,将每个字母,一个个按照位置进行排列,形成最终的Z字排列效果。

实现步骤:

  1. 检查特殊情况

    • 如果numRows等于1,或者numRows大于或等于字符串s的长度,直接返回原始字符串,因为Z字形变换在这些情况下没有必要或没有意义。
  2. 初始化数据结构

    • 创建一个二维字符数组rows,其大小为numRows乘以字符串长度。这个数组将用于存储Z字形的每一行。
    • 初始化变量currentRow为0,表示当前填充的行。
    • 初始化布尔变量goingDown,用于指示当前移动方向是向下还是向上。
  3. 填充二维数组

    • 使用for循环遍历字符串s中的每个字符。
    • 将当前字符放入rows数组的currentRow行的当前索引位置。
    • 检查currentRow是否在第一行或最后一行,如果是,则切换goingDown的值,以改变移动方向。
    • 根据goingDown的值更新currentRow,如果goingDowntrue,则currentRow递增;否则递减。
  4. 构建结果字符串

    • 创建StringBuilder对象result,用于高效地构建最终的字符串。
    • 使用嵌套的for循环遍历rows数组的每一行和每一行中的每个字符。
    • 对于每个字符,如果它不是初始值(在Java中,字符数组的初始值是0,但这里应该是空字符'\u0000'),则将其追加到StringBuilder对象中。
  5. 返回结果

    • StringBuilder对象转换为字符串,并返回这个字符串,它是Z字形变换后的字符串。

实现代码1:

public String convert(String s, int numRows) {
    // 如果只有1行或者需要的行数大于或等于字符串的长度,直接返回原始字符串
    if (numRows == 1 || numRows >= s.length()) {
        return s;
    }

    // 创建一个二维字符数组,每个子数组的大小为s的长度,用于存储每一行的字符
    char[][] rows = new char[numRows][s.length()];
    
    // 初始化当前行索引为0,表示从第一行开始填充
    int currentRow = 0;
    
    // 初始化方向标志,false表示向上移动,true表示向下移动
    boolean goingDown = false;

    // 遍历字符串s中的每个字符
    for (int i = 0; i < s.length(); i++) {
        // 将当前字符放入二维数组的相应位置
        rows[currentRow][i] = s.charAt(i);
        
        // 如果当前行是第一行或最后一行,改变移动方向
        if (currentRow == 0 || currentRow == numRows - 1) {
            goingDown = !goingDown;
        }
        
        // 根据当前的移动方向更新currentRow的值
        // 如果goingDown为true,currentRow递增,否则递减
        if (goingDown) {
            currentRow++; 
        } else {
            currentRow--;
        }
    }

    // 创建StringBuilder对象用于构建最终的字符串结果
    StringBuilder result = new StringBuilder();
    
    // 遍历二维数组的每一行
    for (char[] row : rows) {
        // 遍历行中的每个字符
        for (char c : row) {
            // 过滤掉未赋值的位置
            if (c != '\u0000') {
                result.append(c);
            }
        }
    }
    
    // 将StringBuilder对象转换为字符串并返回
    return result.toString();
}

为了方便字符串拼接操作,使用了StringBuilder类和增强的for循环,如果有忘记StringBuilder类这个知识点的朋友可以看看反转字符串中的单词 一题,可以写写,也可以看后面的知识补充。

实现思路2:对思路一进行了小小优化,提高了执行效率

  1. 输入验证:检查numRows是否小于等于1或者大于等于字符串s的长度。如果是,则直接返回原始字符串,因为不需要进行Z字形变换。

  2. 初始化行数组:创建一个StringBuilder数组rows,其长度为numRows。数组中的每个元素都将用于构建Z字形变换后的每一行。

  3. 初始化当前行和方向:设置currentRow为0,表示当前填充的行。goingDown标志用来指示当前是在向下填充(true)还是向上填充(false)。

  4. 遍历字符串:遍历输入字符串s中的每个字符。

  5. 添加字符到当前行:将当前字符添加到rows数组的currentRow索引处的StringBuilder对象中。

  6. 更新方向:如果当前行是第一行或最后一行,翻转goingDown的值,以改变填充方向。

  7. 移动到下一行:根据goingDown的值,更新currentRow。如果goingDowntruecurrentRow递增;如果为falsecurrentRow递减。

  8. 重复填充:继续遍历字符串,重复步骤5-7,直到所有字符都被添加到相应的行。

  9. 拼接结果:创建一个StringBuilder对象result,用于拼接最终的Z字形字符串。遍历rows数组,将每个StringBuilder对象转换成字符串并追加到result

  10. 返回结果:将result转换成字符串并返回,这是Z字形变换后的最终结果。

实现代码2:

public String convert(String s, int numRows) {
    // 特殊情况处理:如果只有1行或者行数大于字符串长度,直接返回原始字符串
    if (numRows <= 1 || numRows >= s.length()) {
        return s;
    }

    // 创建一个二维数组,每个子数组代表一行,长度为字符串的长度
    StringBuilder[] rows = new StringBuilder[numRows];
    for (int i = 0; i < numRows; i++) {
        rows[i] = new StringBuilder();
    }

    // 遍历字符串中的每个字符
    int currentRow = 0; // 当前行
    boolean goingDown = false; // 是否向下移动

    for (char c : s.toCharArray()) {
        rows[currentRow].append(c); // 将字符添加到当前行

        // 判断移动方向
        if (currentRow == 0 || currentRow == numRows - 1) {
            goingDown = !goingDown;
        }

        // 根据移动方向更新当前行号
        currentRow += goingDown ? 1 : -1;   
    }

    // 将所有行的字符串拼接起来,形成最终的Z字形字符串
    StringBuilder result = new StringBuilder();
    for (StringBuilder row : rows) {
        result.append(row);
    }

    return result.toString();
}

   currentRow += goingDown ? 1 : -1 等价于

if (goingDown) {
    currentRow += 1; // 如果goingDown为true,currentRow增加1
} else {
    currentRow -= 1; // 如果goingDown为false,currentRow减少1
}

  • 13
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值