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
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/zigzag-conversion 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、题解:
(1)方法1:按行排序:
使用 min(numRows,len(s))
个列表来表示 Z 字形图案中的非空行。
从左到右迭代 s,将每个字符添加到合适的行。可以使用当前行和当前方向这两个变量对合适的行进行跟踪。
只有当我们向上移动到最上面的行或向下移动到最下面的行时,当前方向才会发生改变。
class Solution {
public String convert(String s, int numRows) {//("PAYPALISHIRING",3)
if (numRows == 1) return s;
List<StringBuilder> rows = new ArrayList<>();
for (int i = 0; i < Math.min(numRows, s.length()); i++)//0 1 2
rows.add(new StringBuilder());// 结果为[ , , ]
int curRow = 0;//flag
boolean goingDown = false;
for (char c : s.toCharArray()) {//P A Y P A L I S H I R I N G
//增强for循环
//toCharArray() 方法将字符串转换为字符数组
rows.get(curRow).append(c);//调用List型的rows的get方法得到Stringbuilder型的字符,再用append方法,结果为:[P, , ]
if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;//true
// if (curRow == 0 || curRow == numRows - 1){
// goingDown = !goingDown;
//}
curRow += goingDown ? 1 : -1;//goingDown为true则+1,为false则-1
}
//最终得到结果[P,A,Y]
// [ ,P, ]
// [A,L,I]
// ...
StringBuilder res = new StringBuilder();//创建res对象
for (StringBuilder row : rows) res.append(row);//rows[1]={P,A,H,N} ...
return res.toString();
}
}
复杂度分析:
时间复杂度:O(n),其中n==len(s)
空间复杂度:O(n)
作者:LeetCode 链接:https://leetcode-cn.com/problems/zigzag-conversion/solution/z-zi-xing-bian-huan-by-leetcode/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
知识点:
①List:
/**1、Collection接口:单列集合(单列数据),用来存储一个一个的对象
* >List:元素有序、可重复的集合。-->”动态“数组
* >ArrayList、LinkedList、Vector
* List接口概述:
* 鉴于Java中数组用来存储数据的局限性,通常使用List来替代数组,“动态数组”
* List集合类中元素有序、可重复,集合中的每个元素都有其对应的顺序索引
* List荣放弃中的元素都对用一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
* JDK API中List接口的实现类常有的有:
* --ArrayList:作为List接口的主要实现类。线程不安全的、效率高;底层使用Object[] elementData存储。
* --LinkedList:对于频繁的插入和删除操作,使用此类效率比ArrayList高;底层使用双向链表存储。
* --Vector:作为List接口的老实现类。线程安全,效率不高。底层使用Object[] elementData存储。
*
* List接口中的常用方法:
* add(int index,Object ele):在index位置插入ele元素
* addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来
* get(int index):获取指定index位置的元素
* indexOf(Object obj):返回obj在当前集合中首次出现的位置
* LastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
* remove(int index):移除指定index位置的元素,并返回此元素
* set(int index,Object ele):设置指定index位置的元素为ele
* subList(int fromIndex,int toIndex):返回从fromIndex到toIndex的子集合
*
*/
②StringBuilder:
/**
常用类:
String、StringBuffer、StringBuilder三者的异同?
String:不可变的字符序列,底层使用char[]存储
StringBuffer:可变的字符序列,线程安全的,效率低;底层使用char[]存储
StringBuilder:可变的字符序列,JDK5.0新增的。线程不安全的,效率高;底层使用char[]存储
源码分析:
String str =new String(); //底层结构 char[] value=new char[0];
String str1=new String("abc"); //char[] value=new char[]{'a','b','c'};
StringBuffer sb1=new StringBuffer(); //char[] value=new char[16];底层创建了一个长度时16的数组。
System.out.println(sb1.;length()); //
sb1.append('a'); //value[0]='a';
sb1.append('b'); //value[1]='b';
StringBuffer sb2=new StringBuffer("abc");//char[] value=new char["abc".length()+16]
//问题1.System.out.println(sb2.length());//3
//问题2.扩容问题:如果要添加的数据底层数组盛不下啦,那就要扩容底层的数组。
默认情况下,扩容我i原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。
指导意义:开发中建议大家使用StringBuffer(int capacity)
·
* StringBuffer类的常用方法
* StringBuffer append():
* StringBuffer delete():
* StringBuffer replace():
* StringBuffer insert():
* StringBuffer reverse():
* public int indexOf(String str)
* public String substring(int start,int end):返回一个从start开始到索引结束的左闭右开区间的额子字符串。
* public int length()
* public char charAt(int n)
* public void setCharAt(int n,char ch)
*/
(1)方法2:按行访问:
class Solution {
public String convert(String s, int numRows) {
if (numRows == 1) return s;
StringBuilder ret = new StringBuilder();
int n = s.length();
int cycleLen = 2 * numRows - 2;
for (int i = 0; i < numRows; i++) {
for (int j = 0; j + i < n; j += cycleLen) {
ret.append(s.charAt(j + i));
if (i != 0 && i != numRows - 1 && j + cycleLen - i < n)
ret.append(s.charAt(j + cycleLen - i));
}
}
return ret.toString();
}
}
复杂度分析
作者:LeetCode
链接:https://leetcode-cn.com/problems/zigzag-conversion/solution/z-zi-xing-bian-huan-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间复杂度:O(n),其中 n==len(s)。每个索引被访问一次。
空间复杂度:O(n)。对于 C++ 实现,如果返回字符串不被视为额外空间,则复杂度为 O(1)。