題目:
將字符串 "PAYPALISHIRING" 以Z字形排列成給定的行數:
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
解法1:這是一種很笨的方法,一開始一位規律會很難找,所以就想到用這種方法先做出來再說,
class Solution {
public String convert(String s, int numRows) {
if(numRows==1){
return s;
}
StringBuilder str = new StringBuilder();
List<char[]> list = new ArrayList<>(); //存儲整個的Z形的所有列
int size = 0,len = s.length();
for(int i = 0;i<len;i++){
char[] chars = new char[numRows]; //存儲每一列的數據
int remainder = i%(numRows-1); //計算餘數,確定是否是整列
for(int j = remainder==0?0:numRows-1-remainder;j<numRows-remainder;j++){ //如果是整列起點爲0,否則爲numRows-1-remainder
chars[j] = s.charAt(size++); //把列上的數據填到對應位置
if(size>=len){ //全部遍歷完跳出循環
break;
};
}
list.add(chars); //把每一列的數據加入集合
if(size>=len){
break;
};
}
for(int j = 0;j<numRows;j++){ //遍歷集合把爲默認值的char排除拼接起來
for(int i = 0,length = list.size();i<length;i++){
char[] chars = list.get(i);
if(chars[j]!='\u0000'){
str.append(chars[j]);
}
}
}
return str.toString();
}
}
這裏就是把每一列的數據都遍歷出來,以char數組的結構存到以list上,然後再通過遍歷把不是默認值的字符拼接起來,其實這裏如果用二維數組可能效果會好一點,在第二遍歷的時候空間複雜度會小一點;
時間複雜度:O(n)
空間複雜度:O(n^2)
解法2:
class Solution {
public String convert(String s, int numRows) {
int length = s.length();
if(length<=1||numRows<=1){ //特殊參數情況處理
return s;
}
StringBuilder str = new StringBuilder();
for(int i = 0;i<numRows;i++){ //一行一行遍歷出字符
int num = i;
while(num<length){
str.append(s.charAt(num));
if(i!=0&&i!=numRows-1&&num+2*(numRows-1-i)<length){ //如果不是第一行和最後一行,把單獨的一個字符拼接
str.append(s.charAt(num+2*(numRows-1-i)));
}
num += 2*(numRows-1); //一個循環的等差
}
}
return str.toString();
}
}
這個方法直接遍歷拼接字符串,因爲我們可以找到對應的規律,先不考慮中間空缺的列,每一行對應的數對應的等差爲2*(numRows-1);接下來考慮特殊情況,即不在第一行和最後一行的時候,把多餘的一個字符加入進來,這裏也可以發現規律,如果行數爲num,則兩個的差值爲2*(numRows-1-num);所有直接遍歷拼接出字符串,比起第一種解法少了求出每一列的計算。而且空間複雜度也小很多。提交的數據第一個時間爲89ms,第二種解法爲39ms;
時間複雜度:O(n);
空間複雜度:O(n)