首页 > 试题广场 >

Z字形字符串

[编程题]Z字形字符串
  • 热度指数:10360 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

字符串"ZXYZXLISHIRING"写成3行的Z字形的样式如下:

Z   X   H   N
X Z L S I I G
Y   I   R


按行读这个Z字形图案应该是 "ZXHNXZLSIIGYIR"

请编写代码完成将字符串转化为指定行数的Z字形字符串:

示例1

输入

"AB",2

输出

"AB"
0     4     8
1  3  5  7  9
2     6    10
可以发现 当行数为3的时候 每4个数组成一个周期
行数为nRows的时候 周期t= 2*nRows-2
[0,nRows-1) 向下 [nRows,t) 向上
初始化一个 nRows 行的vector 依次将string中的每一个放入,在合并。

 class Solution  {
 public:
     string convert(string s, int nRows) {
         if (nRows <= 1) return s;
         int t = nRows + nRows - 2; //求出循环周期
         string res="";
         vector<string> m(nRows, res);
         for (int i = 0; i < s.length(); i++)
         {
             int a = i%t;
             if (a < nRows)  //往下走
                 m[a]+=s[i];
             else            //往上走
                 m[t - a ] += s[i];
         }
         for (int i = 0; i < nRows; i++)
             res += m[i];   //合并
         return res;
     }
 };

编辑于 2018-05-24 22:15:08 回复(6)
// 定义nRows长度的stringbuffer数组,存放每一行的结果  // 先从0~nRows,再从nRows-2~0
public class Solution {
    public String convert(String s, int nRows) {
        if(s == null || s.length() == 0 || nRows <= 1)
        	return s;
        
        StringBuffer[] sb = new StringBuffer[nRows];
        for(int i = 0; i < sb.length; i++)
        	sb[i] = new StringBuffer();
        
        int len = s.length();
        int i = 0;
        while(i < len){
        	for(int j = 0; j < nRows && i < len; j++)
        		sb[j].append(s.charAt(i++));
        	for(int j = nRows - 2; j > 0 && i < len; j--)
        		sb[j].append(s.charAt(i++));
        }
        
        for(int j = 1; j < nRows; j++)
        	sb[0].append(sb[j]);
        
        return sb[0].toString();
    }
}

发表于 2017-06-07 22:20:43 回复(4)
不需要额外的存储
string convert(string s, int nRows) {
        // 计算下标可得
        // 第一行下标之间的间隔为2*nRows-2,从0开始
        // 第二行下标由第一行下标分别-1和+1得到(除去<0和>字符串长度的)
        // 第三行下表由第一行下标分别-2和+2得到(除去<0和>字符串长度的)
        // 直到第nRows行
        if (nRows <= 1) return s;
        string res = ""; // 必须初始化为""
        int lenS = s.length();
        // 第一行
        for (int i = 0; i < lenS; i += 2 * nRows - 2) res += s[i];
        // 中间行
        for (int row = 1; row < nRows - 1; row ++) {
            res += s[row];
            for (int i = 2 * nRows - 2; i - row < lenS; i += 2 * nRows - 2) {
                if (i - row >= nRows) res += s[i - row];
                if (i + row < lenS) res += s[i + row];
            }
        }
        // 最后一行,因为最后一行不能由第一行加和减得到,会重复,所以单独拿出来
        for (int i = nRows - 1; i < lenS; i += 2 * nRows - 2) res += s[i];
        
        return res;
    }

发表于 2019-06-11 10:27:51 回复(0)
//这个题目搞循环控制搞了1个小时。。。**,感觉要爆炸。 
这个是Z字形来走的
A        E          I
  B    D    F    H
    C         G
这样来弄,只有第一行和最后一行的都是nRows*2 -2;
中间的行要分上下两个方向来走
如果从下往上走,那么中间的间隔为count + size - 2 * i; 然后另外一种情况的间隔为size。
中间的一些变量请参考代码。
class Solution {
public:
    string convert(string s, int nRows) {
        if(s == "" || s.size() <= 1 || nRows <= 1) return s;
        string ans = "";
        int size = nRows*2 -2;
        for(int i = 0 ; i != nRows ; ++i)
        {
            int count = i;
            while(count < s.size())
            {
                ans += s[count];
                if(i > 0 && i < (nRows-1))
                {
                    int tmp = count + size - 2 * i;
                    if(tmp < s.size()) ans += s[tmp];
                }
                count = count + size;
            }
        }
        return ans;
    }
};

发表于 2018-03-11 15:10:11 回复(0)
/*举例子:1-20的数字,nRows = 5,输出结果应当为1 9 17 2 8 10 16 18 3 7 11 15 19 4 6 12 14 20 5 13
1           9              17
2        8  10         16  18
3     7     11      15     19
4  6        12  14         20
5           13
对于第一行和最后一行,每个数之间间隔2*nRows - 2

对于中间行而言:
第二行:(1)2,10,18之间仍然间隔2*nRows - 2
       (2)2,8之间间隔6,可表示为2*nRows - 2 - 2,同理对于10和16也是
第三行:(1)3,11,19之间间隔2*nRows - 2
       (2)3,7之间间隔4,可表示为2*nRows - 2 - 2*2,同理对于11和15也是
第三行:(1)4,12,20之间间隔2*nRows - 2
       (2)4,6之间间隔2,可表示为2*nRows - 2 - 2*3,同理对于12和14也是
       
通过发现以上规律,我们可以得到解题思路:
对于第一行和最后一行,通过简单的循环单独处理,一个个将字符加入到结果集中

对于中间行,每循环一次将每两个字符加入到结果集中,但是要判断字符是否存在越界访问情况
如上面例子第二行2和8,10和16,对于18,其加上间隔2*nRows - 2 - 2*2后字符访问越界
*/
public class Solution {
    public String convert(String s, int nRows) {
        if(s == null || s.length() == 0 || nRows <= 1)
            return s;
        int len = s.length();
        //使用StringBuffer运行效率更高
        StringBuffer res = new StringBuffer();
        //单独处理第一行
        for(int i = 0; i < len; i += 2*nRows - 2){
            res.append(s.charAt(i));
        }
        //处理中间行
         int k = 1;
         for(int i = 1; i < nRows - 1; i++){
              for(int j = i; j < len ; j += 2*nRows - 2){
                  res.append(s.charAt(j));
                  //判断字符访问是否越界
                  if((j + 2*nRows - 2 - 2*k) < len){
                      res.append(s.charAt(j + 2*nRows - 2 - 2*k));
                  } 
              }
             k++;
         }
         //单独处理最后一行
         for(int i = nRows - 1; i < len; i += 2*nRows - 2){
             res.append(s.charAt(i));
         }
         return res.toString();
    }
}

编辑于 2019-07-18 13:21:46 回复(0)
public class Solution {
    public String convert(String s, int n) {
        if(s==null || s.length()==0 || n==1)
            return s;
        //StringBuilder必须初始化,否则报空指针异常
        StringBuilder[] sb=new StringBuilder[n];
        for(int m=0;m<sb.length;m++)
            sb[m]=new StringBuilder();
        
        StringBuilder res=new StringBuilder();
        boolean flag=true;
        for(int i=0,j=0;i<s.length();i++)
        {
            sb[j].append(s.charAt(i));
            if(j==n-1 && flag)
                flag=false;
            if(j==0 && !flag)
                flag=true;
            j=flag?j+1:j-1;
        }
        for(StringBuilder sbb :sb)
            res.append(sbb.toString());
        return res.toString();
    }
}

发表于 2019-06-05 23:56:08 回复(0)
/**
* 给出字符串s以及行数nRows,
* 把字符串s摆放成之字型的字符串,且一共占据nRows行
* 如,给出字符串s = 0123456789ABCDEF,
* 当nRows = 2时,
* 0 2 4 6 8 A C E
* 1 3 5 7 9 B D F
* 
* 当nRows = 3时,
* 0   4   8   C
* 1 3 5 7 9 B D F
* 2   6   A   E
*
* 当nRows = 4时,
* 0     6     C
* 1   5 7   B D
* 2 4   8 A   E
* 3     9     F
*
* 思路:模拟生成过程
* 通过循环模拟“之”字走过的路径,
* 使用nRows个StringBuilder计算、保存最终每行的结果,
* 记迭代变量为i,遍历s,
* 当由上往下时,每个StringBuilder依次加入一个字符s[i++];
* 当由下往上时,除头尾两个StringBuilder外,依次加入一个字符s[i++],
* 直到i = s.length()。
* 最后合并每个StringBuilder。
**/
public class Solution {
    public String convert(String s, int nRows) {
        if (s == null || s.length() < 1 || nRows < 2) {
            return s;
        }
        StringBuilder[] sb = new StringBuilder[nRows];
        for (int i = 0; i < nRows; i++) {
            sb[i] = new StringBuilder();
        }
        int i = 0;
        while (i < s.length()) {
            for (int j = 0; j < nRows && i < s.length(); j++) {
                sb[j].append(s.charAt(i++));
            }
            for (int j = nRows - 2; j > 0 && i < s.length(); j--) {
                sb[j].append(s.charAt(i++));
            }
        }
        for (int k = 1; k < nRows; k++) {
            sb[0].append(sb[k]);
        }
        return sb[0].toString();
    }
}

发表于 2018-11-29 21:32:59 回复(1)
class Solution {
public:
    string convert(string s, int nRows) 
    {
     if(nRows<=1)
            return s;
    vector<string> zigzag(nRows,"");
   int step = 1,i=0,row = 0;
   for(int i=0;i<s.length();i++)
   {
      zigzag[row] += s[i];
      if(row == nRows-1)   /// 确定开始向上还是向下
        step = -1;
      else if(row==0)
        step = 1;
      row += step;
   }
   string res = "";
   for(string temp : zigzag)
    res += temp;
   return res;  
  }
};

发表于 2017-07-12 09:22:10 回复(1)
const int maxn=927;
class Solution {
    char G[maxn][maxn];
public:
    string convert(string s, int nRows) {
        int len=s.length();
        if(!len) return "";
        if(nRows==1) return s;
        int i,j,index,flag=0,k;
        for(i=0;i<maxn;i++)
            for(j=0;j<maxn;j++) G[i][j]='#';
        for(i=0,j=0,index=0;index<len;index++){
            G[i][j]=s[index];
            if(flag==0){
                i++;
                if(i+1==nRows) flag=1;
            }else{
                i--,j++;
                if(i==0) flag=0;
            }
        }
        string res="";
        for(i=0;i<nRows;i++)
            for(j=maxn-1;j>=0;j--)
                if(G[i][j]=='#') G[i][j]='$';
                else break;
        for(i=0;i<nRows;i++){
            for(j=0;j<maxn;j++)
                if(G[i][j]=='#') res+="";
                else if(G[i][j]=='$') //i+1!=nRows?res+="\n":res=res;
                    break;
                else res+=G[i][j]; 
        }
        return res;
    }
};

发表于 2017-10-24 22:02:25 回复(0)
class Solution {
public:
    string convert(string s, int nRows) {
        if(nRows <= 1)
        	return s;
        vector<string> z(nRows,"");
        int step = 1,row = 0;
        int l = s.length();
        for(int i=0;i<l;i++)
        {
        	z[row] += s[i];
        	if(row == 0)
        		step = 1;
        	else if(row == nRows-1)
        		step = -1;
        	row += step;
		}
		string result = "";
		for(int i=0;i<nRows;i++)
        	result += z[i];
        return result;
    }
};


发表于 2017-08-20 01:00:54 回复(0)
public static String convert(String s, int nRows) {
		if (nRows <= 1) return s;
		char[] str = new char[s.length()];  //用字符数组存储结果,StringBuilder也会爆内存。
		int k = 0, i = 0, j = 0;
		for (j = 0; j < nRows; j++) {   //j为行序    
		//找到字符顺序规则,对于每行(第一列为行序)然后以2(rows-1)的大小递增,对于中间行还要加一次单个的字符位置为 当前位置i+2(nRows-j-1)
			for (i = j; i < s.length(); i = i + 2 * (nRows - 1)) {
				str[k++] = s.charAt(i);
				int len2 = i + 2 * (nRows - j - 1);
				if (j != 0 && j != (nRows - 1) && len2 < s.length())
					str[k++] = s.charAt(len2);
			}
		}
		return String.valueOf(str);
	}

发表于 2017-08-16 13:37:53 回复(0)
class Solution {
public:
    string convert(string s, int nRows) {
           if(nRows<=1) return s;//注意特判==1的情况,因为这时2*nRows-2不会增长了
           string ans;
           int sz=s.size();
           for(int i=0;i<nRows;i++){
               if(i==0||i==nRows-1){
                  int k=i;
                  while(k<sz) ans+=s[k],k+=2*nRows-2;  
               }else{
                  int l=i,r=2*nRows-2-i;
                  while(l<sz||r<sz){
                       if(l<sz) ans+=s[l],l+=2*nRows-2;
                       if(r<sz) ans+=s[r],r+=2*nRows-2;  
                  } 
               }
           }
           return ans;
    } 
};

发表于 2017-08-09 10:03:44 回复(0)
public String convert(String s, int numRows) {
		if (s == null || s.length() < numRows)
			return s;
		StringBuffer[] sb = new StringBuffer[numRows];
		for (int i = 0; i < numRows; i++) {
			sb[i] = new StringBuffer();
		}

		char[] c = s.toCharArray();
		int len = s.length();
		int index = 0;
		while (index < len) {
			for (int i = 0; i < numRows && index < len; i++) {
				sb[i].append(c[index++]);
			}
			for(int i=numRows-2;i>0&& index < len;i--){
				sb[i].append(c[index++]);
			}
		}
		
		for(int i=1;i<numRows;i++){
			sb[0].append(sb[i]);
		}
		return sb[0].toString();
	}

发表于 2017-07-05 13:27:10 回复(0)
谁能告诉我,为啥注释代码会运行超时呢?就是第一行的字母是斜着写的管还是竖着写的管,差别很大吗?
public String convert (String s, int nRows) {
        int index=0;
        StringBuilder[] sb=new StringBuilder[nRows];
        for(int i=0;i<nRows;i++) {
            sb[i]=new StringBuilder();
        }
        for(int i=0;i<nRows;i++) {
            sb[i]=new StringBuilder();
        }
         int x=0;
        while(index<s.length()) {
            while(x<nRows&&index<s.length()) {
                sb[x++].append(s.charAt(index++));
            }
            x=nRows-2;
            while(x>0&&index<s.length()) {
                sb[x--].append(s.charAt(index++));
            }
            x=0;
            
            /*
            while(x>=0&&index<s.length()) {
                sb[x--].append(s.charAt(index++));
            }
            x=1;
            */
        }
        for(int i=1;i<nRows;i++) {
            sb[0].append(sb[i]);
        }
		return sb[0].toString();
    }


发表于 2021-02-07 23:14:10 回复(0)
14ms 9800KB
import java.util.*;


public class Solution {
    /**
     * 
     * @param s string字符串 
     * @param nRows int整型 
     * @return string字符串
     */
    public String convert (String s, int nRows) {
        // write code here
        if (s == null || s.length() <= 2) return s;
        StringBuilder sb = new StringBuilder();
        int k = (nRows - 1) << 1;
        int i = 0;
        while(i < s.length()) {
            sb.append(s.charAt(i));
            i += k;
        }
        for(int row = 1; row < nRows - 1; ++row) {
            i = row;
            int kk = k - (row << 1);
            while(i < s.length()) {
                sb.append(s.charAt(i));
                if (i + kk >= s.length()) 
                    break;
                sb.append(s.charAt(i+kk));
                i += k;
            }
        }
        i = nRows - 1;
        while(i < s.length()) {
            sb.append(s.charAt(i));
            i += k;
        }
        return sb.toString();
    }
}


发表于 2020-07-29 16:26:38 回复(0)
思路:用flag标记 “从上往下” “从下往上”
注意:使用StringBuffer才有append函数,并且一定要new(不然会报错)
 
import java.util.*;

public class Solution {
    /**
     * 
     * @param s string字符串 
     * @param nRows int整型 
     * @return string字符串
     */
    public String convert (String s, int nRows) {
        // write code here
        if(nRows<=1 || s.length()<=1 || nRows>=s.length())
            return s;
        
        int flag = -1;
        int num = s.length();
        
        StringBuffer[] row = new StringBuffer[nRows]; 
        //一定要new
        for(int k=0;k<nRows;k++)
        {
            row[k]=new StringBuffer();
        }
        
        int i=0;
        while(i<num)
        {
            if(flag==-1) //从上往下走
            {
                for(int j=0;j<nRows-1;j++)
                {
                    row[j].append(s.charAt(i));
                    i++;
                    if(i==num)
                        break;
                }
                flag= (-1)*flag;
            }
            else       //从下往上走
            {
                for(int j=nRows-1;j>=1;j--)
                {
                    row[j].append(s.charAt(i));
                    i++;
                    if(i==num)
                        break;
                }
                flag=(-1)*flag;
            }
        }
        
        for(int k=1;k<nRows;k++)
        {
            row[0].append(row[k]);
        }
        
        return row[0].toString();
    }
}


发表于 2020-07-12 22:23:52 回复(0)
借鉴楼上各位大佬的解法;模拟之字形;利用   nRows 个stringBuilder分别存储每行的char;
*记迭代变量为i,遍历s,
* 当由上往下时,每个StringBuilder依次加入一个字符s[i++];
* 当由下往上时,除头尾两个StringBuilder外,依次加入一个字符s[i++],
* 直到i = s.length()。
* 最后合并每个StringBuilder。
import java.util.*;
public class Solution {
    /**
     * 
     * @param s string字符串 
     * @param nRows int整型 
     * @return string字符串
     */
    public String convert (String s, int nRows) {
        // write code here
        if(s==null || s.length()<1 ||nRows < 2) return s;
        StringBuilder []str = new StringBuilder[nRows];
        for(int i=0;i<nRows;i++){
            str[i] = new StringBuilder();
        }
        int i=0;
        while(i<s.length()){
            for(int j=0;j<nRows && i<s.length();j++){
                str[j].append(s.charAt(i++));
            }
            for(int j=nRows-2;j>0 && i<s.length();j--){
                str[j].append(s.charAt(i++));
            }
        }
        for(int k=1;k<nRows;k++){
            str[0].append(str[k]);
        }
        return str[0].toString();
    }
}



发表于 2020-07-11 17:35:42 回复(0)
起点(0,0),把往下走看作i,把往右走看作j.
每次先往下,在往斜上方走。然后拼接同一行的字符串,之后在拼接每一行的字符串。
class Solution:
    def convert(self , s , nRows):
        if s==""&nbs***bsp;nRows==1: return s
        pos = dict()
        i, index, length = 0, 1, len(s)
        pos[0] = s[0]
        while index < length:
            # 先往下走
            k = 0
            while k < nRows-1 and index < length:
                i = i + 1
                pos[i] = pos.get(i, "") + s[index]
                index = index + 1
                k = k + 1
            # 斜着往上走
            k = 0
            while k < nRows-1 and index < length:
                i = i - 1
                pos[i] = pos.get(i, "") + s[index]
                index = index + 1
                k = k + 1
        ans = ""
        for key, value in pos.items():
            ans += value
        return ans


发表于 2020-07-08 15:11:29 回复(0)
function convert( s ,  nRows ) {
    // write code here
    var arr = new Array(nRows);
    var str = '';
    var index = 0;
    var flag = false;
    for(var i = 0; i < s.length; i++){
        if(i%(nRows-1) == 0){
            flag = !flag
        }
        if(arr[index]){
            arr[index] += s[i]
        }else{
            arr[index] = s[i]
        }
        if(flag){
            index++
        }else{
            index--
        }
    }
    for(var k in arr){
        str += arr[k];
    }
    return str
}

发表于 2020-06-18 12:21:14 回复(0)
import java.util.*;
public class Solution {
    public String convert (String s, int nRows) {
        // write code here
        if(nRows==1)return s;
        int[] dir = {1,-1};
        List<String> list = new ArrayList();
        for(int i=0;i<nRows;i++)list.add("");
        int j=0,k=0;
        for(int i=0;i<s.length();i++){
            list.set(j,list.get(j)+s.charAt(i));
            if(j+dir[k]>list.size()-1||j+dir[k]<0)k=(k+1)%2;
            j+=dir[k];
        }
        String res="";
        for(int i=0;i<nRows;i++){
            res+=list.get(i);
        }
        return res;
    }
}
发表于 2020-06-09 13:54:30 回复(0)