記事ディレクトリ
タイトル説明
1.1、直接的な思考
トピックを見て、考える方法:
class Solution {
public String convert(String s, int numRows) {
char[]str = s.toCharArray();
if(numRows<=1){
return s;
}
char[][]res = new char[numRows][s.length()/2+1];
int k=0;
int j=0;
int l=0;//列索引
int i=0;//行索引
while(j<str.length){
if(k==0){
//向下走
for(i=0;i<numRows&&j<str.length;i++){
res[i][l] = str[j];
j++;
}
k=1;//改变方向
l++;//走到了尽头,列加1
}
if(k==1){
//开始向上走
int row = numRows-2;
for(i=l;row>0&&j<str.length;i++){
res[row][i]= str[j];
row--;
j++;
}
l=i;
k=0;
}
}
StringBuilder sb = new StringBuilder();
for(int b=0;b<res.length;b++){
for(int t=0;t<res[b].length;t++){
if('\u0000'!=res[b][t]){
//char数组默认值为0的字符值'\u000'
sb.append(res[b][t]);//遍历组合输出
}
}
}
return sb.toString();
}
}
1.2、初めての最適化のための直接的な思考
不要な量を削除します。
class Solution {
public String convert(String s, int numRows) {
char[]str = s.toCharArray();
if(numRows<=1){
return s;
}
char[][]res = new char[numRows][s.length()/2+1];
int j=0;
int l=0;//列索引
int i;//行索引
while(j<str.length){
//向下走
for(i=0;i<numRows&&j<str.length;i++){
res[i][l] = str[j];
j++;
}
l++;
int row = numRows-2;
for(i=l;row>0&&j<str.length;i++){
//斜向上走
res[row][i]= str[j];
row--;
j++;
}
l=i;
}
StringBuilder sb = new StringBuilder();//提取数据
for (char[] re : res) {
for (char c : re) {
if ('\u0000' != c) {
sb.append(c);
}
}
}
return sb.toString();
}
}
上記のアルゴリズムは、主に2次元配列の追加によるものです。これには、多くのnull値があり、O(N 2)の時間の複雑さにつながります。したがって、文字列の方向をシミュレーションして追加します。
1.3、2番目の最適化、使用の種類を変更する
2次元配列を変更します。List<StringBuilder>
タイプになる
各StringBuilderはデータの行を表すため、n個のStringBuilderがあります。方向はフラグで示されます。最初と最後の行でのみ、フラグの値とトレンドが変化することがわかります。次のコードを使用できます。
class Solution {
public String convert(String s, int numRows) {
if(numRows<2){
return s;
}
//模拟走向
List<StringBuilder> resRow = new ArrayList<>();
for(int i=0;i<numRows;i++){
resRow.add(new StringBuilder());//创建n行空字符串
}
int index=0,flag=1;//1表示向下走
for(char k:s.toCharArray()){
resRow.get(index).append(k);//刚开始是想下走
index+=flag;//开始走,向下则索引加1
if(index==0||index==numRows-1){
//遇到末行就要向上走,遇到首行方向重新向下走。
flag=-flag;
}
//这样,在模拟走的过程中我们不需要添加'\u0000';加大空间利用率
}
StringBuilder res =new StringBuilder();//将每行的字符串进行组合输出
for(StringBuilder k:resRow){
res.append(k.toString());
}
return res.toString();
}
}
時間の複雑さに関しては、O(N)として推定する必要があります。空間の複雑さは次のとおりです。O(N);
2.1、達成する法律を見つける
最後に、提出の失敗の割合から、それがまだ最適化されている必要があることがわかります。データの分布は定期的である必要があります。結果はより速くなる可能性があります。したがって、次のルールを見つけます。
行から、最初の行は8、0として理解されます。2番目の行の8-2*1,0+2*1
区間インデックスは最後の行のインデックスです8-2*(n-1),0+2*(n-1)
。だからあなたはコードを書くことができます:
class Solution {
public String convert(String s, int numRows) {
if(numRows<2){
return s;
}
List<StringBuilder> list = new ArrayList<>();
for(int i=0;i<numRows;i++){
list.add(new StringBuilder());
}//n行空字符串
int dlter=2*(numRows-1);//找到间隔初值
char[] chars = s.toCharArray();
for(int i=0;i<numRows&&i<chars.length;i++){
list.get(i).append(chars[i]);//初始化第一个值
int col;//间隔
if(i==0||i==numRows-1){
//间隔为dlter、0
col = i+dlter;
while(col<chars.length){
list.get(i).append(chars[col]);
col+=dlter;
}
}else {
//间隔为d1和d2;
int d1 = dlter-2*i;
int d2 = dlter-d1;
col = i+d1;//d1的间隔
while(col<chars.length){
list.get(i).append(chars[col]);
if((col+=d2)<chars.length)
list.get(i).append(chars[col]);
col+=d1;//8-2=6,下一次就是8-6=2
}
}
}
StringBuilder res =new StringBuilder();//将每行的字符串进行组合输出
for(StringBuilder k:list){
res.append(k.toString());
}
return res.toString();
}
}
2.2、法律で最適化を見つける
上記のアプリケーションでは、追加した要素がインラインで追加されていることがわかりました。したがって、最終的なマージ操作は必要ありません。そのため、StringBuilderを1つだけ使用して実現できます。
class Solution {
public String convert(String s, int numRows) {
if(numRows<2){
return s;
}
StringBuilder list = new StringBuilder();
int dlter=2*(numRows-1);//找到间隔初值
char[] chars = s.toCharArray();
int n=chars.length;
for(int i=0;i<numRows&&i<n;i++){
list.append(chars[i]);//初始化第一个值
int col;//间隔
if(i==0||i==numRows-1){
//间隔为dlter、0
col = i+dlter;
while(col<n){
list.append(chars[col]);
col+=dlter;
}
}else {
//间隔为d1和d2;都大于0
int d1 = dlter-2*i;
int d2 = dlter-d1;
col = i+d1;//d1的间隔
while(col<n){
list.append(chars[col]);
if((col+=d2)<n)
list.append(chars[col]);
col+=d1;//8-2=6,下一次就是8-6=2
}
}
}
return list.toString();
}
}
最後に、効率は完全に改善されます: