LeetCode 06Z字形变换&07整数反转

简介: 将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:

Z字形变换



题意


题目描述


将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:


L   C   I   R
E T O E S I I G
E   D   H   N


之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);


示例 1:

输入: s = “LEETCODEISHIRING”, numRows = 3

输出: “LCIRETOESIIGEDHN”


示例 2:

输入: s = “LEETCODEISHIRING”, numRows = 4

输出: “LDREOEIIECIHNTSG”

解释:


L     D     R
E   O E   I I
E C   I H   N
T     S     G


分析


对于这题该如何处理呢?首先要理解题意,它就是本来给一个字符串,然后要按照Z字形排列等到一个形状,根据这个形状按照从左往右的顺序取值得到一个新的字符串。


20200814174519496.png


法一模拟法:


既然这个字符串是固定的,那么我们是否可以模拟这个过程?


  • of course you can 模拟。你可以定义一个二位数组,根据Z字形的这个排列规律,先向下(同时横坐标不变),再向上(同时考虑横坐标增加)一直到最后,然后对二维数组进行遍历取值(不空的值。)


这样当然可以,但是模拟真的有必要这么搞嘛?当然没必要。二维数组占据太多无用的空间浪费内存。我们其实可以对内存进行优化考虑:


20200814180244683.png


这样只需要考虑上下两个方向往集合中添加元素,最终就可以实现啦。不过在字符串叠加时候尽量不要使用String直接加,会很慢。这种方法只能干掉40%的人,一般般。


ac代码为:


public String convert(String s, int numRows) {
      List<Character> list[]=new ArrayList[numRows];
      for(int i=0;i<numRows;i++)
      {
        list[i]=new ArrayList<Character>();
      }
      int index=0;
      boolean up=false;//方向 初始向下
      for(int i=0;i<s.length();i++)
      {
        list[index].add(s.charAt(i));
        if(numRows==1) {continue;}
        if(up)//向上
        {
          if(index==0)
          {
            index++;up=false;
          }
          else {
          index--;
        }
        }
        else {
        if(index==numRows-1)
        {
          index--;up=true;
        }
        else {
          index++;
        }
        }
      }
      StringBuilder builder=new StringBuilder();
      for(int i=0;i<numRows;i++)
      {
        for(int j=0;j<list[i].size();j++)
        {
          builder.append(list[i].get(j));
        }
      }
      return builder.toString();  
  }


法二数学分析


上面的一种方法为模拟Z字形操作的整个流程,需要往里添加,取值也需要遍历取值。我们能不能用另一种角度去思考问题呢?


因为每次只加一个字符,我们如果按照以下的思路看待这个问题(原字符串弯曲),从每一层看,能不能找到每一层有什么规律呢?


20200814181620649.png


  • 第一层是 0 6 12也就是 0 0+(n-1)*2 0+(n-1)*3
  • 第二层两个求位置关系,可不可以看成第一层每个位置-1和+1两个位置(越界不考虑)?
  • 第三层和第二层同理,看成第一层的-2和+2不越界的位置
  • 最后一层单独考虑


这样整个逻辑分析就完成了,可以根据位置添加元素进去再取值。ac的代码如下:


public String convert(String s, int numRows) {
        if(numRows==1)return s;
     List<Character> list[]=new ArrayList[numRows];
     for(int i=0;i<numRows;i++)
     {
      list[i]=new ArrayList<Character>();
     }
     //处理第一行最后一行
     for(int i=0;i<s.length();i+=(numRows-1)*2)
     {
       list[0].add(s.charAt(i));
       if(i+numRows-1<s.length())
       {
         list[numRows-1].add(s.charAt(i+numRows-1));
       }
     }
     for(int i=0;i<s.length()+numRows;i+=(numRows-1)*2)
     {
       for(int j=1;j<numRows-1;j++)//中间所有行
       {
         int index1=i-j;
         int index2=i+j;
         if(index1>=0&&index1<s.length())
           list[j].add(s.charAt(index1));
         if(index2>=0&&index2<s.length())
           list[j].add(s.charAt(index2));
       }
     }
      StringBuilder builder=new StringBuilder();   
      for(int i=0;i<numRows;i++)
      {
        for(int j=0;j<list[i].size();j++)
        {
          builder.append(list[i].get(j));
        }
      }
      return builder.toString();
    }


但这种方法也只能干掉40%+的人,该如何优化呢?


首先,该方法先存到List[]再取,其实是遍历两次,其实大可不必这样,我们可以在进行计算每一层的同时加入到结果中。


其次,由于边界的问题我们需要考虑太多的边界问题,我们对此对中间层的考虑优化,两个节点位置通过计算这样组合,可以优化边界的if else判断。


20200814183414257.png


注意一些细节情况,最终ac的代码为:


public static String convert2(String s, int numRows) {
     if(numRows==1)return s;
     //处理第一行
     StringBuilder builder=new StringBuilder();
     for(int i=0;i<s.length();i+=(numRows-1)*2)
     {
       builder.append(s.charAt(i));
     }
     for(int i=1;i<numRows-1;i++)
     {
       for(int j=0;j<s.length()+numRows;j+=(numRows-1)*2)//中间所有行
       {
         int index1=j+i;
         int index2=j+(numRows-1)*2-i;
         if(index1<s.length())
          builder.append(s.charAt(index1));
         if(index2<s.length())
          builder.append(s.charAt(index2));
       }
     }
     for(int i=numRows-1;i<s.length();i+=(numRows-1)*2)
     {  
       builder.append(s.charAt(i));
     }
      return builder.toString();
  }


最终的效果还行(偶尔三毫秒):


20200814183631936.png


整数反转



20200814183905838.png


这题的话注意以下数组越界问题,可以用long类型处理最终再用整形处理。


主要有两种处理方法,一个就是转成字符串处理,第二个就是用数值处理。但是一般尽量不要用字符串处理比较慢。


ac代码为:


public  int reverse(int x) {
     if(x==0)return 0;
     String value=x+"";
     if(value.charAt(0)=='-')
       value=value.substring(1);
     StringBuilder sb=new StringBuilder();
     for(int i=value.length()-1;i>=0;i--)
     {
       sb.append(value.charAt(i));
     }
     long num=Long.parseLong(sb.toString());
     if(x<0)num=-num;
     if(num<Integer.MIN_VALUE||num>Integer.MAX_VALUE)
     {
       return 0;
     }
     return (int)num;
   }


数值类型处理方式为:


 public int reverse(int x) {
     if(x==0)return 0;
     long num=0;
     while (x%10==0) {
      x/=10;
    }
     int t;
     while (x!=0) {
        t=x%10;//各位
      num=num*10+t;
      x/=10;
      if(num>Integer.MAX_VALUE||num<Integer.MIN_VALUE)
        return 0;
    }
     return (int)num;  
   }


时间还行:


20200814194720924.png


结语



本次两题稍容易一些,再接再厉,注意方法的优化。

欢迎关注公众号:bigsai,回复进群,一起打卡LeetCode!

目录
相关文章
|
22天前
|
存储
LeetCode整数反转
解决LeetCode上的整数反转问题的几种方法,包括错误的方法和优化后的解决方案,以及如何避免反转后的整数超出32位有符号整数范围的问题。
30 1
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
102 2
|
24天前
【LeetCode】整数翻转
【LeetCode】整数翻转
13 1
|
22天前
|
存储 C++
Leetcode第十二题(整数转罗马数字)
LeetCode第12题“整数转罗马数字”的解题方法,包括罗马数字的基本规则和特殊规则,以及如何使用C++实现整数到罗马数字的转换。
14 0
|
22天前
|
C++
Leetcode第十三题(罗马数字转整数)
这篇文章介绍了LeetCode第13题“罗马数字转整数”的解题方法,通过一个C++的类`Solution`中的`romanToInt`函数来实现,该函数使用哈希表和遍历字符串的方法,根据罗马数字的规则将输入的罗马数字字符串转换为对应的整数值。
43 0
|
22天前
|
算法 C++
Leetcode第八题(字符串转换整数(atoi))
这篇文章介绍了LeetCode上第8题“字符串转换整数(atoi)”的解题思路和C++的实现方法,包括处理前导空格、正负号、连续数字字符以及整数溢出的情况。
14 0
|
3月前
|
算法
LeetCode第12题目整数转罗马数字
该文章介绍了 LeetCode 第 12 题整数转罗马数字的解法,通过使用 TreeMap 按照整数从大到小排序,先使用大的罗马数字表示整数,再用小的,核心是先表示完大的罗马数字,想通此点该题较简单。
LeetCode第12题目整数转罗马数字
|
3月前
|
算法
LeetCode第8题字符串转换整数 (atoi)
该文章介绍了 LeetCode 第 8 题字符串转换整数 (atoi)的解法,需要对字符串进行格式解析与校验,去除前导空格和处理正负号,通过从高位到低位的计算方式将字符串转换为整数,并处理越界情况。同时总结了这几道题都需要对数字的表示有理解。
LeetCode第8题字符串转换整数 (atoi)
|
3月前
|
算法
LeetCode第7题整数反转
该文章介绍了 LeetCode 第 7 题整数反转的解法,通过除 10 取模和乘 10 累加的方式实现整数反转,同时注意边界情况的判断,并总结了通过举例推算发现规律的解题思路。
LeetCode第7题整数反转
|
3月前
|
算法
LeetCode第13题目罗马数字转整数
该文章介绍了 LeetCode 第 13 题罗马数字转整数的解法,通过从大到小解析罗马数字,根据罗马数字的特点,按照从大到小的顺序匹配罗马数字和整数的关系,从而解决该问题,同时强调要注意观察题目考查的知识点特征。