力扣06 Z字形变换

力扣 6 Z字形变换

方法一 硬刚法

首先,我们硬刚他:

image-20220105203020104

最开始的想法就是做numRows个list,按顺序原来字符串的顺序轮着赋值,如下图所示,然后返回list1+list2+list3+list4的拼接。

image-20220105203332344

也就是遍历原字符串,从1到length,依次追加到表 list1 list2 list3 list4。

注意这个赋值给列表的顺序,如果把列表一到列表四放到一个一位数组里,那么他们的下标将 是如下顺序:

​ 1 2 3 4 3 2 1 2 3 4 3 2 1 2 .....

以下是代码,重要的是需要考虑如何编程构造上述的顺序:

class Solution {
    public String convert(String s, int numRows) {
        int len = s.length();
//特殊情况,要求划分一行1的时候,直接返回原来字符串。
       if(numRows==1)return s;
//原字符串转字符数组     
       char[] chars = s.toCharArray();
//用于存放答案
       String ans = "";
        
        
        
//这里的列表用StringBuffer实现会方便一些,同时为了方便遍历,构造了一个StringBuffer的一位数组。并初始化对象。       
        StringBuilder[] a = new StringBuilder[numRows];   
        for(int i = 0;i<numRows;i++){
            a[i] = new StringBuilder("");
        }

        
//遍历数组,并依次给这n个表追加当前的字符串。        
        int count = -1;int i = 1;
        for(char c : chars){
            
            count+=i;
            a[count].append(c);

            
            //下边是两个边界的情况
    		//当count到达最后一行的时候,改变自增量,使其切换方向,
            //使其实现行数由大变小,由小变大,由大变小,,,,的循环
            if(count==numRows-1){i=-1;}
            if (count==0){i=1;}        
        }
        
        
//下面就是拼接这几个StringBuffer        
        for(StringBuilder b :a){
            ans+=b.toString();
        }
//
        return ans;

    }
}

然而。。。

image-20220105205753224

说明实际的算法并不如想象的那么费劲,,,,吃完饭后仔细观察了一下他的格式发现了以下规律。

方法二 仔细观察法

考虑到原字符串和目标字符串长度内容完全一直,只是顺序不一致,按理说一次遍历就能解决问题,下面再看一下那个Z字图:

image-20220105203020104

1.首末行的规律

对于第一行和最后一行,他们作为一个循环内的拐点,

image-20220105210525905

红线为原来的字符串顺序,假设有n行(这里n=4),那么第一行的第i个和第i+1个,正好为原字符串中每隔5个的取值。(正好少了绿框框中的那些字符)

所以:第一行和最后一行是一样的,确定好首个字符后,每隔2n-1遍历原字符数组即可。

注意是每隔2n-1,对于这种情况就是每次+6遍历

2.中间行的规律

不难发现,这个z字型其实是一个周期的图形

image-20220105212647204

比方对于一共四行的

他的第二行是隔三个遍历然后隔一个遍历,,,,

就是每次先+4遍历再+2遍历。。。。。


同理第三行是隔个一个遍历,然后每隔三个遍历

image-20220105214146945

先+=2再+=4

你会发现他们的和始终是6(其实第一行和最后一行可以退化成 +=0 然后 +=6)

综上: 对于n=4的情况:

​ 你只需要维护一个和原字符串相同长度的数组res[], int count=0;设原字符串数组为s

  1. ​ res[count++] = s[temp+=6] 直到temp+6超出s.length
  2. ​ res[count++] = s[temp+=4] 然后 res[count++] = s[temp+=2] 直到超出
  3. ​ res[count++] = s[temp+=2] 然后 res[count++] = s[temp+=4] 直到超出
  4. ​ res[count++] = s[temp+=6] 直到temp+6超出s.length

然后返回res的字符串即可

方法二最后总结

设一共让你分n行,

1第一行,在原字符串中 每 +=(2n-1) 取值赋给 设定的数组res

2中间行(i行),先 += 2n-1-2i 取值,再 +=2i取值 ,赋值给res

3最后一行,和第一行一样 在原字符串中每+=2n+1(也就是每隔)取值,赋值给res

最后上个代码: (写得有点啰嗦,谁能优化一下子?)

class Solution {
    public String convert(String s, int numRows) {
      
  //特殊情况,当只要求分一行,或要求分的行数比字符串长度还长的时候,直接返回字符串
       if(numRows==1||s.length()<=numRows) return s;

       int len = s.length();
       char[] map = s.toCharArray();
        //res是存放答案的数组
       char[] res = new char[len];
      //count是用来赋值的指针 res[count]    
       int count = 0;
      //current是在原字符串上跳跃遍历的指针map[current]
        int current =0;
       
        
 //对于第一行       
         int first = 0;current=0;res[count++] = map[first+current];
                while(first+current<len){
                  current+=(2*numRows-2);
                   if(first+current<len)res[count++] = map[first+current];
           }
        
 //对于中间行  
           for(int i =1;i<numRows-1;i++){
               //这里有细节要注意一下, 这个先自增a再自增b的这种规律
               //不一定完全,由于字符串的长度不一定,随时戛然而止,
               //所以每次做自增的时候都要判断是否已经遍历完数组
               //不然就会出现数组下标越界的情况。
                current = 0; res[count++] = map[i+current];
               while(i+current<len){
                  current+=(2*numRows-2*i-2);
            if(i+current<len)res[count++] = map[i+current];
                  current+=(2*i);
              if(i+current<len)res[count++] = map[i+current];
               }
           }              
  
        
  //对于最后一行
                int last = numRows-1;current=0;res[count++] = map[last+current];
                while(last+current<len){
                  current+=(2*numRows-2);
                   if(last+current<len)res[count++] = map[last+current];
           }
      


    
       return new String(res);
    }
}

不过结果还可以

image-20220105205713947

posted @ 2022-01-05 22:09  淮南枳  阅读(115)  评论(0)    收藏  举报