链表实现 Z 字形变换

题目:

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如给定字符串 PAYPALISHIRING 行数为4的时候排列图如下。
在这里插入图片描述
然后再再逐行读取拼接成 PINALSIGYAHRPI

题目分析:

通过上面的excel我们可以看出和坐标轴很像,一个是X轴,一个是Y轴。

step 1: 拆分多个单元。处理一个单元,剩余单元采用递归的形式处理。

在这里插入图片描述

step 2 : 每个单元的元素个数是: int eachUnitElementCount = numRows + numRows - 2

在这里插入图片描述

step 3 :单元总数计算: int units > = s.length() % eachUnitElementCount == 0 ? s.length() / eachUnitElementCount : s.length() /eachUnitElementCount + 1;
题目实例 14个元素, 每个单元6个元素。 得出 一共3个单元。

step 4: 现在的 Y轴是 numRows 。 X轴元素单元。 我们先循环Y轴,再逐个循环单元取到值。
在这里插入图片描述

step 5 : 分析每个单元,一个单元内的第一行 是 1个元素, 最后一行是1个元素,剩余的都是2个元素。

step 6 : 单元内每个元素的角标计算。 i = 行数 (从0开始) , j = 单元数(从1开始)

  1. 每个单元 6个元素。
  2. 第一行是1个元素,最后一行是 1个元素。其余行理论上是2个元素。
  3. 第一行,第一个单元角标 0。 第二个单元角标 6 ,第三个单元角标 12. 带入公式。eachUnitElementCount * (j - 1) + i 。 (i = 0)
  4. 第二行有两个元素,第一个元素角标是 i + eachUnitElementCount * (j- 1)。 每个单元内同一行的两个元素角标之和肯定等于 eachUnitElementCount。所以第二个元素的角标是
    eachUnitElementCount * j - i

代码实现

public class Solution{
	
	/** 用户存放新数据的链表, 哨兵节点 **/
	private Node head = new Node();

	/** 链表的末尾节点 **/
	private Node tail ;

	/** 每个单元的元素个数 **/
	private int eachUnitElementCount;

	/** 单元个数 **/
	private int units;


	/** 转换 **/
	public String convert(String s, int numRows){
		if(numRows == 1){return s;}
		this.eachUnitElementCount = 2 * numRows - 2;
		this.units = s.length() % eachUnitElementCount == 0? s.length()/eachUnitElementCount : s.length()/eachUnitElementCount + 1;

		int i = 0;
		/** 遍历 Y轴 **/
		while(i < numRows){
			int j = 1;
			/** 遍历 X轴的单元 **/
			while(j <= units){
				/** 单元格内第一个待进队列角标 **/
				int firstIndex = i + (j -1) * eachUnitElementCount;
				/** 单元格内第二个待进队列角标 **/
				int lastIndex = j * eachUnitElementCount - i;
				if(i == 0 && firstIndex < s.length()){
					enNode(s.charAt(firstIndex));
				} else if(i == numRows - 1 && lastIndex < s.length()){
					enNode(s.charAt(lastIndex));	
				} else {
					if(firstIndex < s.length()){enNode(s.charAt(firstIndex));}
					if(lastIndex < s.length()){enNode(s.charAt(lastIndex));	}
				}
				j ++;
			}
			i++;
		}
		return changeNodeToString(head);
	}





	/** 把链表内元素转成字符串的方法 **/
	public String changeNodeToString(Node head){
		if(head == null || head.next == null){return null;}
		head = head.next;
		StringBuilder sb = new StringBuilder();
		while(head != null){
			char ele = head.getData();
			sb.append(ele);
			head = head.next;
		}

		return sb.toString();
	}


	/** 把一个元素插入链表的方法 **/
	public boolean enNode(char ele){
		Node temp = new Node();
		temp.setData(ele);
		if(tail == null){
			tail = temp;
			head.next = tail;
		} else {
			tail.next = temp;
			tail = temp;
		}
		return true;
	}

	/** 链表结构 **/
	class Node{
		private char data;
		private Node next;
		public char getData() {
            return data;
        }

        public void setData(char data) {
            this.data = data;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }
	}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值