LeetCode 6. ZigZag Conversion题解

题目

6. ZigZag Conversion

The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)

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

And then read line by line: “PAHNAPLSIIGYIR”

Write the code that will take a string and make this conversion given a number of rows:

string convert(string s, int numRows);

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

分析

依据题意,此题最关键的显然就是找出所有字符所在的行数,这样才能以行的顺序将新的字符串返回。
为了找出字母与行之间的关系,我们需要发掘一些规律:

思路一:移动方向

动态考虑Z型字符串在竖直方向上的产生过程,比如:
在这里插入图片描述
就是先从P开始,以↓表示向下走,以↑表示向上走,即为P↓A↓Y↑P↑A↓L↓I……
不难发现箭头的朝向是有规律的:
只有在字符到达第一行(curRow==1)或最后一行(curRow==numRows)时,方向才会发生切换。

思路二:静态分组

我们不考虑Z字型字符串的产生过程,直接考虑其最终结果,将之分组。
在这里插入图片描述
也就是每次当字符重新回到第一行时,会产生新的一组。
这样分组以后,我们只需要知道每个字母在它所在的那组中的位置,就可以得到它的行数了。因为每组的结构都是完全一样的(都是两列,且左列numRows行,右列numRows - 2行)。
而除了最后一组以外,每组的个数是groupNum = (2 * numRows - 2)(numRows > 1时才成立)。
在分组以后,对于每组,我们不难发现:(假设当前行为 i,行从0开始数)
i == 0i == numRows-1时(也就是第一行和最后一行),该组内都只有一个字符满足。
i为其他值时,该组内总有两个字符满足。这两个字符在组中的位置分别是 i 和 groupNum - i。
综上所述,我们只需先将原先的字符串 s 进行分组,然后对于组进行遍历,就可以得到每行的字符串了。


题解

Java实现思路一

import java.util.ArrayList;
import java.util.List;

class Solution {
    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();
    }
}

C++实现思路一

class Solution {
    public:

    string convert(string s, int numRows) {
        if (numRows == 1) return s;
        vector<string> rows (min(numRows, int(s.size())));
        int curRow = 0;
        bool goingDown = false;
        for (char c : s) {
            rows[curRow] += c;
            if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
            curRow += goingDown ? 1 : -1;
        }
        string ret;
        for (string row : rows) ret += row;
        return ret;
    }
};

以上两个都是LeetCode的官方题解。

Java实现思路二

import java.util.ArrayList;
import java.util.List;

public class Solution {

    public String convert(String s, int numRows) {
        StringBuilder returnString = new StringBuilder();
        if(numRows == 1)return s;
        int groupNum = numRows * 2 - 2;//一组的个数
        List<String> groups = new ArrayList<>();
        for(int i=0;i<s.length();i+=groupNum){//分组
            if(i + groupNum <= s.length()) {
                groups.add(s.substring(i, i + groupNum));
            }else{
                groups.add(s.substring(i,s.length()));
            }
        }
        for(int i=0;i<numRows;i++){//按行输出,从第一行到最后一行
            for(String group:groups){
                if(i == 0){
                    //打印该组第一行(仅一个字符)
                    returnString.append(group.charAt(0));
                }
                else if(i == numRows - 1){
                    //打印该组最后一行(仅一个字符)
                    if(numRows - 1 < group.length()) {
                        returnString.append(group.charAt(numRows - 1));
                    }
                }else{
                    //打印该组其他行(两个字符,index分别是i和groupNum-i)
                    if(i < group.length()) {//确保数组访问不越界(也就是考虑到最后一组的特殊情况)
                        returnString.append(group.charAt(i));
                    }
                    if(groupNum-i < group.length()) {
                        returnString.append(group.charAt(groupNum-i));
                    }
                }

            }
        }
        return returnString.toString();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值