力扣面试经典算法150题:Z 字形变换

42 篇文章 0 订阅
21 篇文章 0 订阅

Z 字形变换

今天的题目是力扣面试经典150题中的数组的中等难度题: Z 字形变换。

题目链接:https://leetcode.cn/problems/zigzag-conversion/description/?envType=study-plan-v2&envId=top-interview-150

题目描述

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

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

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

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

  • 示例 1:

    • 输入:
      s = “PAYPALISHIRING”, numRows = 3

    • 输出:
      “PAHNAPLSIIGYIR”

    • 解释:

      P	  A	    H	  N 
      A  P  L  S  I  I  G 
      Y	  I	    R
      
  • 示例 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”

    • 解释:
      没法转换,直接返回字符串

题目分析

题目会给定一个字符串和一个数字num,要求把字符串分成num行。在分行的时候,要求按列Z字形排列。

其实这个Z字形可能不是很直观,再拆分成一个类似字的左边的竖提就清晰一点。

用示例来讲解一下:

  1. 示例一:
    P-A-Y-P组成第一个竖提,A-L-I-S组成第二个竖提,H-I-R-I组成第三个竖提,最后的N-G组成一个不完整的竖提。
  2. 示例二:
    P-A-Y-P-A-L组成第一个竖提,I-S-H-I-R-I组成第二个竖提,N-G组成最后一个不完成的竖提。

仔细观察,是不是知道了怎么按行数排列字符串了。

排列好字符串以后,我们从左到右,从第一排到最后一排,把数组全部拼接起来即可。

解题思路

目前来看,以作者的水平这个题目没有能够方便使用的算法,只能暴力破解。

  1. 首先确认拼接方式,我们按行数循环,凭借每行的字符,因为题目要求我们从左往右拼接给出结果。
  2. 确认每行中每列字符在字符串中的索引。根据前面的分析,三行的时候四个字符组成一个竖提,也就是说,每次循环需要四个字符,四行的时候六个字符组成一个竖提,我们自己再尝试两行,五行等情况.
    最后你会发现每次循环的字符数 = 2*(num - 1)。 2 = 2*(2-1),4 = 2*(3-1),6 = 2*(4-1),8 = 2*(5-1)。。。。。
  3. 那么我们可以创建num个数组,每个数组 存放一行的内容。
  4. 循环字符串,使用当前下标对当前行数对应的字符数取模,取模的值与行数比较,如果小于行数的,直接使用当前取模值为当前行数。否则使用字符数减去取模值。注意因为我们循环是从0开始,所以这里的实际行数应该加1。比如取模值为0,实际是第一行。
  5. 拼接所有行的字符。

根据以上分析,我们可以编写实现代码。

实际算法代码

以下是暴力解答的代码实现:

public class ZigzagConversion {
	
	 public static void main(String[] args) {
        ZigzagConversion solution = new ZigzagConversion();
        System.out.println(solution.convert("PAYPALISHIRING", 3)); // 输出 "PAHNAPLSIIGYIR"
        System.out.println(solution.convert("PAYPALISHIRING", 4)); // 输出 "PINALSIGYAHRPI"
     }
	
     public String convert(String s, int numRows) {
        // 行数是1的矩阵或者行数就等于字符串长度的,直接返回字符串本身
        if (numRows == 1 || numRows >= s.length()) return s;

        // 定义一个数组,用来存储每一行的字符串
        StringBuilder[] rows = new StringBuilder[numRows];
        // 定义每行的拼接对象,注意行数 = i-1
        for (int i = 0; i < numRows; i++) {
            rows[i] = new StringBuilder();
        }

        // 获取字符串长度用于循环
        int n = s.length();
        // 获取每次循环时构成Z性的字符长度
        int cycleLen = 2 * numRows - 2;

        // 循环字符串
        for (int i = 0; i < n; i++) {
            // 取模
            int rowIndex = i % cycleLen;
            // 小于行数的索引,行数就等于索引,大于的用字符数减取模值,因为此时从下往上排列
            if (rowIndex < numRows) {
                rows[rowIndex].append(s.charAt(i));
            } else {
                rows[cycleLen - rowIndex].append(s.charAt(i));
            }
        }

        // 拼接结果
        StringBuilder result = new StringBuilder();
        for (StringBuilder row : rows) {
            result.append(row);
        }

        return result.toString();
    }
}

结果

运行程序,正常输出答案:

在这里插入图片描述

提交到力扣,也通过测试:

在这里插入图片描述

总结

又是暴力解答的一题,没有已经归纳好的算法,单纯就是总结规律加上字符串数组循环拼接的基础知识。

善于分析归纳,扎实的基础,基本上没有解不出的题目,暴力解答也是解答,别拿豆包不当干粮,是吧?

准备直面困难题目了,加油!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值