LeetCode 006 ZigZagConversion
来源:互联网 发布:图片热点 js 边框 编辑:程序博客网 时间:2024/04/30 02:53
6. ZigZag Conversion
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H NA P L S I I GY I R
And then read line by line: "PAHNAPLSIIGYIR"
Write the code that will take a string and make this conversion given a number of rows:
string convert(string text, int nRows);
convert("PAYPALISHIRING", 3) should return "PAHNAPLSIIGYIR".
class Solution {public: string convert(string s, int numRows) { }};
解题思路:
- 自己的解题思路
一开始认为题目很简单,但是实际操作起来,发现自己的思路实现起来并没有那么简单。似乎这种感觉经常会出现。所以,不能眼高手低,一定要实现出来,绝不能想当然。
思路:
首先,将zigzag图案的每行的列数算出来;如下,
P A H N ………………………………………… col[0]=4A P L S I I G ………………………………………… col[1]=7Y I R ………………………………………… col[2]=3
然后计算结果res;依次从每行开始遍历,然后对于每行的每一列进行遍历,运用相应的行列对应公式就可以得出结果。
总评:对应公式比较复杂,期间调试很久。这真是一个糟糕的算法。
- 别人的解题思路
[1] 第一个方法很巧妙,它将每一个ZigZag图案拉长,变成锯齿形图案。
P A H N A P L S I I G Y I R
利用辅助数组string[nRows],记录每行的string,然后链接就可以得到结果。
好处,不需要复杂的源字符串与目的字符串的对应公式。
[2] 第二个方法,跟我的思路比较靠近,但是它的思路更清晰。
首先对应一个cycle=2*nRows – 2;这相当于步长,但是出去首行跟末行,其他行还有中间一个元素需要对应,因此在循环中还需要一个判断条件。
学习收获:
- 对边界条件(Boundary Conditions)加深理解
自己写的程序,一开始没有考虑边界条件。总是,直接提交,然后再看通不过的测试案例,然后再修改。虽然最后也能通过,但是在CCF认证考试,浙大的PAT考试,找工作的机试都是只能提交代码的。偶尔的系统还会告诉你,这个程序有没有全部通过测试案例,但是几乎全不会像LeetCode这么人性化还给你错误的案例。因此,必须对此加以重视,否则要找不到工作的节奏。
总结一下:这次犯的错误。
边界条件,主要就是对输入的把控。
- 如果程序中,有除法运算,一定要记得考虑是否除数为0的情况。
- 对于string,考虑size()为0的情况。对于int,考虑为0 以及正负数的情况。
本题,没有考虑到负数的情况,说明我的程序还是有漏洞的,需要重视。别人的程序就有考虑。
- 对于string部分的初始化、size以及capacity理解更深。
string a(10); //no exist such initialization but vector<int> a(10) is okaystring a(10,’\0’) //but you can do like this
对于一个string a;需要时刻考虑他的size以及capacity。
eg: string a;
a.reserve(10); //PS:reserve()的效果是只增不减
a[6]=’x’; //就是会报错的,reserve只是改变了capacity,而不是size
对于string的其他相关知识,可以参考附件2。
- Word技巧:如何左右观看同一个文档,以及上下观看同一个文档。
【左右】点视图->新建窗口。 之后,会出现同一个Word文档的窗口。特点,一个窗口改变,一个窗口的Word也会同步改变。
之后,再点->并排查看 默认的情况是:同步滚动的,意思就是向下拉一个窗口,另一个窗口也在往下拉。而一般是不需要这个并排查看的,再点击一下,就可以去除。
之后,就是可以完美左右查看文档。
关闭方法:直接关闭一个窗口就可以。
【上下】点视图->拆分;就可以上下观看同一个文档的两个不同部分。
关闭方法,再次点击拆分,即可。
附件:程序
1、自己的程序:
string convert(string s, int numRows) { //boundary conditions: (1) s.size()==0; (2) numRows == 1 //what about other impossible instances eg:numRows == 0 if(s.size() == 0) { return string(); } else if(numRows == 1) { return string(s.begin(), s.end()); } //initialize res, but we cannot do like this: string res(sz); int sz = s.size(); string res(sz, '\0'); //col[] is to store every row's length vector<int> col(numRows, 0); //compute col[0] col[0] = (sz - 1) / ((numRows << 1) - 2) + 1; //compute col[ 1, 2, ..., numRows-2 ] for(int i = 1; i < numRows - 1; ++i) { if(sz - ((numRows - 1)*((col[0] - 1) << 1) + 1 + i) < 0) { col[i] = (col[0] - 1) << 1; } else if(sz - ((numRows - 1)*((col[0] - 1) << 1) +(numRows << 1) - i - 1) < 0) { col[i] = (col[0] << 1) - 1; } else { col[i] = col[0] << 1; } } //compute col[numRows-1] if(sz - ((numRows - 1)*((col[0] - 1) << 1) + numRows) < 0) { col[numRows - 1] = col[0] - 1; } else { col[numRows - 1] = col[0]; } //to get the res for(int index = 0, i = 0; i < numRows&&index != sz; ++i) { if(i == 0 || i == numRows - 1) { for(int j = 0; j != col[i]; ++j) { res[index++] = s[(((numRows - 1)*j) << 1) + i]; } } else { for(int j = 0; j != col[i]; ++j) { if(j % 2 == 0) { res[index++] = s[(j >> 1)*((numRows - 1) << 1) + i]; } else { res[index++] =s[(j >> 1)*((numRows - 1) << 1) + (numRows << 1) - i - 2]; } } } } return res; }
2、别人的程序
string convert(string s, int nRows) { if(nRows <= 1) return s; const int len = (int)s.length(); string *str = new string[nRows]; int temp = (len - 1) / ((nRows << 1) - 2) + 1; int limits = temp << 1; for(int i = 0; i < nRows; ++i) { str[i].reserve(limits); } int row = 0, step = 1; for(int i = 0; i < len; ++i) { str[row].push_back(s[i]); if(row == 0) step = 1; else if(row == nRows - 1) step = -1; row += step; } s.clear(); for(int j = 0; j < nRows; ++j) { s.append(str[j]); } delete[] str; return s; }string convert(string s, int nRows) { if(nRows <= 1) return s; string result = ""; //the size of a cycle(period) int cycle = 2 * nRows - 2; for(int i = 0; i < nRows; ++i) { for(int j = i; j < s.length(); j = j + cycle) { result = result + s[j]; //j-i 回跳到之前尖点[行号为0], +cycle 则是跳到下一个尖点 //-i 则是回跳到前面的第i行 思路很清晰 int secondJ = (j - i) + cycle - i; if(i != 0 && i != nRows - 1 && secondJ < s.length()) result = result + s[secondJ]; } } return result; }
附件2:扩展阅读(转载)
- C++中string的size,length,capacity三者到底有何区别求解.https://zhidao.baidu.com/question/1048376565616057099.html.
测试发现
1. std::string value(2, ‘a’);
结果: value.size() == value.length()==2; value.capacity()==31
std::string value(31, ‘a’);
结果: value.size() == value.length()==value.capacity()==31;
2. std::string value(32, ‘a’);
结果: value.size() == value.length()==32; value.capacity()==63;
std::string value(63, ‘a’);
结果: value.size() == value.length()==value.capacity()==63;
3. std::string value(80, ‘a’);
结果: value.size()==value.length()==80; value.capacity()==95;
std::string value(95, ‘a’);
结果: value.size()==value.length()==value.capactiy()==95;
举这3个例子不难发现
a) . size() 和 length() 效果一样,不过C++的话,倾向于用 size();
b) . string的容量,也就是capactiy(),如果 value值为空,则capactiy()==0;
否则,capacity() 初始值为32,根据string 存储的量的变化而变化
初始值=31,步长=32;
【原创】点评
当然,这个各个机器不一样,比如有初始值=15,步长=16。至于为什么31,而不是32,因为\0原因。字符串前后都有\0,但是无法利用*(s.end());*(s.rend())取出,可以用operator[]查看。
- C++容器中 size(), capacity, reserve() ,resize() 函数讲解.http://blog.csdn.net/youxin2012/article/details/9213539
【原创】点评
关于size和capacity,以及reserve()讲解的不错,遗憾的是对于resize()没有结合实例,进行深入讲解。
附件3:扩展阅读(自我总结)
好好总结一下size,capacity
至于size(),capacity()的大小关系,以及相应的编译器的分配原则,上面的参考资料已经讲解的很清楚。我这里主要介绍关于capacity,size(等价于length,string为了统一性所以加入size()。由于length()之前就有,加上名字也很合适,造成了一些冗余尴尬)。
由于string类里面关于capacity的相关操作比较全,我们就以capacity进行总结。主要涉及9个成员函数,详细见下图。
(1)首先,介绍有return值得几个成员函数。
size(),length() //等价,返回字符串大小; capacity() //返回分配的内存空间的大小。这个不是指分配给对象string s的大小,而是对象里面有个指针,也就是s.c_str()所指向的对象所获得内存空间max_size() //值就是npos-1 为什么不是npos?可能是为了存放\0吧。 可能值4294967294,不同编译器值可能不一样 这个无需深究
(2)接下来,来看看与size直接相关的成员函数
resize() void resize (size_type n); //n小于目前的size,则截断;如果大于,则使用\0进行初始化多出来的元素void resize (size_type n, charT c); //n小于目前的size,则截断;如果大于,则使用c进行初始化多出来的元素
两个函数原型。
对于size,capacity的影响。
- 对size,直接进行影响,完全控制size的取值。
- 对capacity,如果size变小,没有任何影响;如果size变大,可能会引起capacity的改变。
PS: resize()常用来快速初始化数组,尤其是二维数组。
相关测试程序如下,下面几个成员函数,只要在这个程序的基础上,加加减减就行,所以就不再贴出来。
自己可以跑一下,改改数据。
#include <iostream>#include <string>using namespace std;int main(){ std::string str(200,'\0'); std::cout << "size1: " << str.size() << "\n"; std::cout << "length1: " << str.length() << "\n"; std::cout << "capacity1: " << str.capacity() << "\n"; std::cout << "max_size1: " << str.max_size() << "\n"; str.resize(3); std::cout << "size2: " << str.size() << "\n"; std::cout << "capacity2: " << str.capacity() << "\n"; std::cout << std::string::npos << std::endl; return 0;}
(3)接下来,继续看看与capacity直接相关的几个成员函数
reserve()
void reserve (size_type n = 0);
This function has no effect on thestring lengthand cannot alter its content.
由上面描述可知,对于size,capacity的影响。
- 对size,无法进行任何影响。
- 对capacity,只增不减。
string a{"I Love You"};a.reserve(); //no effecta.reserve(0); //no effecta.reserve(100); //size no change; capacity rise to more than 100 and nearest to 100 就是大于100也是最靠近100的capacity 我的VS结果是111
PS:由于push_back(),超过capacity时,会出现销毁旧内存,重新申请内存等耗时操作。因此,对于多次的push_back(),可以提前指定capacity,这样可以节省运行时间。该技巧在leetcode上面,对于提升性能,效果明显。
void shrink_to_fit(); C++11
Requests thebasic_stringto reduce itscapacityto fit itssize.
This function has no effect on thestring lengthand cannot alter its content.
由于reserve()对capacity的限制,且shrink_to_fit无参数传入,可是理解shrink_to_fit对于capacity只减不增。
由上面描述可知,对于size,capacity的影响。
- 对size,无法进行任何影响。
- 对capacity,只减不增。但不是减到与size相等,而是大于size,且最近size的capacity。
因此,可以得出结论,capacity的值都是系统指定的,我们无法直接控制,但是可以间接控制范围。
(4)最后,介绍几个相关的操作
bool empty() const; //看的是size,而不是capacity。由于是const函数,所以不改变size跟capacity.void clear(); //size to 0; capacity no change
参考资料: cplusplus.com
Constructive comments and reports of errors are always welcome.
Written by Josan.
2016/12/19
0 0
- LeetCode 006 ZigZagConversion
- 【Leetcode】zigzagConversion JAVA
- LeetCode java实现ZigZagConversion
- leetcode #6 ZigZagConversion
- Leetcode——ZigZagConversion
- ZigZagConversion
- 算法--ZigZagConversion
- leetcode6 zigzagConversion
- leetcode-006:ZigZag Conversion
- LeetCode 006 ZigZag Conversion
- LeetCode 006 ZigZag Conversion
- [LeetCode]-006-ZigZag Conversion
- 006 ZigZag Conversion [Leetcode]
- [LeetCode]006-ZigZag Conversion
- LeetCode 006 ZigZag Conversion
- leetcode ZigZag Conversion 006
- LeetCode——006
- LeetCode 006 ZigZag Conversion
- UITabBarItem
- vector的释放问题
- ztree操作当前节点的同级兄弟节点可选
- 判定一个表示时间的字符串与当前时间的间隔
- 算法提高 9-2 文本加密
- LeetCode 006 ZigZagConversion
- xListview
- 【JZOJ4922】环
- Java读入时的一些小问题--next()和nextLine()
- CVPR 2016-12-09
- HDP学习--HDFS Storage(中)
- ArcGIS Engine 9.3二次开发, 打不开ArcGIS10.2创建的mdb
- shell实现1-n 的加法
- [bigdata-006] 工作流 tez和oozie