【做题笔记】: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.length <= 1000;s 由英文字母(小写和大写)、’,’ 和 ‘.’ 组成;1 <= numRows <= 1000)

示例 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”

解法一:

如图一:得出规律,差值2numrows-2,首尾行的起始下标只有一个,分别是0,numrows-1,中间行数起始下标有2个,下标相加是2numrows-2。(此规律容易理解些)在这里插入图片描述
Java代码实现如下:

public String convert(String s, int numRows) {
        /**找规律,以N型为规律,每个N型对应位置之间相差 2 * numRows - 2 下标
         */
        //判断数组长度与numRows行数是否可成多个Z循环(>=1循环)
        if (numRows >= 2 && s.length() > numRows) {

            Map<Integer, ArrayList<Integer>> indexMaps = new HashMap<Integer, ArrayList<Integer>>();
            Map<Integer, String> strMaps = new HashMap<Integer, String>();

            //同一行的字符与起始位 相差 2 * numRows - 2 个位 定义差值
            int diffValue = 2 * numRows - 2;
            //初始化起始行的下标
            ArrayList<Integer> firstList = new ArrayList<Integer>();
            firstList.add(0);
            indexMaps.put(0, firstList);
            strMaps.put(0, s.substring(0, 1));

            //获取后续遍历s的开始位置
            int lastIndex = 0;

            //中间行数有2个index,获取中间行数的起始index 下标相加是2*numrows-2
            for (int i = 1; i < numRows - 1; i++) {
                ArrayList<Integer> indexList = new ArrayList<Integer>();
                indexList.add(i);
                strMaps.put(i, s.substring(i, i + 1));
                if (lastIndex < i) {
                    lastIndex = i;
                }
                //此处加判断,防止组不成一个Z的情况
                if (s.length() > diffValue - i) {
                    indexList.add(diffValue - i);
                    strMaps.put(i, strMaps.get(i) + s.substring(diffValue - i, diffValue - i + 1));
                    if (lastIndex < diffValue - i) {
                        lastIndex = diffValue - i;
                    }
                }
                indexMaps.put(i, indexList);
            }
//初始化最后一行的下标
            ArrayList<Integer> endList = new ArrayList<Integer>();
            endList.add(numRows - 1);
            indexMaps.put(numRows - 1, endList);
            strMaps.put(numRows - 1, s.substring(numRows - 1, numRows));

            if(lastIndex<numRows - 1){
                lastIndex=numRows - 1;
            }

            //若 s.length() > lastIndex + 1 开始遍历后续字符串
            
            for (int i = lastIndex + 1; i < s.length(); i++) {

                out:for (Map.Entry<Integer, ArrayList<Integer>> entry : indexMaps.entrySet()) {
                    ArrayList<Integer> list = entry.getValue();
                    for (int index : list) {
                        //规律  同一行的字符位置数 相差 2 * numRows - 2个位,起始2行只有一个index分别是0,N-1,中间行数有2个index,
                        // 即与起始位置相差x倍数个2* numRows - 2
                        //因此判断相除无余数即可
                        if ((i - index) % (diffValue) == 0) {
                            //每一行拼接字符
                            strMaps.put(entry.getKey(), strMaps.get(entry.getKey()) + s.substring(i, i + 1));
                            break out;
                        }
                    }

                }

            }
            //将拼接好的行数,拼接起来输出
            String res = "";
            for (Map.Entry<Integer, String> entry : strMaps.entrySet()) {
                res = res + entry.getValue();
            }

            return res;

        } else {
            //不满足,直接返回s
            return s;
        }
    }

解法二:

在图一规律上继续找规律,发现在这里插入图片描述
代码实现如下:

public String convert2(String s, int numRows) {
        /**找规律,以N型为规律,每个N型对应位置之间相差 2 * numRows - 2 下标
         */
        //判断数组长度与numRows行数是否可成多个Z循环(>=1循环)
        if (numRows >= 2 && s.length() > numRows) {

            //用数组存放结果
            String[] resChars = new String[numRows];
            //初始化数组
            Arrays.fill(resChars, "");
            //s拆分成数组
            char[] chars = s.toCharArray();

            //同一行的字符与起始位 相差 2 * numRows - 2,定义差值diffValue
            int diffValue = 2 * numRows - 2;
            for (int i = 0; i < chars.length; i++) {
                //取余数
                int mod = i % diffValue;
                //小于numRows 正向取余排序
                if (mod < numRows) {
                    resChars[mod] += chars[i];
                } else {
                    //反向取余排序
                    resChars[diffValue - mod] += chars[i];
                    
                }
            }


            //将拼接好的行数,拼接起来输出
            StringBuilder res = new StringBuilder();
            for (String a : resChars) {
                res.append(a);
            }
            return res.toString();

        } else {

            //不满足,直接返回s
            return s;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值