Given a List of words, return the words that can be typed using letters of alphabet on only one row’s of American keyboard like the image below.
Input: [“Hello”, “Alaska”, “Dad”, “Peace”]
Output: [“Alaska”, “Dad”]
- My train of thought:
一开始想就要用三个数组把三行字母存进去(除了数组真是什么都不会),然后就复习了一下字符数组的相关知识,感觉因为基础语法都忘光了,所以遇到不少问题,下面一句一句地分析我的解法吧。
vector<string> words;
words.push_back("Hello");
words.push_back("Alaska");
words.push_back("Dad");
words.push_back("Peace");
首先遇到的第一个问题是C++容器vector的问题,这里的words是一个string类型的容器
words.push_back() //向尾部添加元素
words.pop_back() //删除最后一个元素
words.size() //读取容器大小
words.resize() //改变容器大小
for (vector<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
{
cout<< *iter << endl;
}
容器的遍历有很多种方法,上面是容器特有的迭代器的方法,当然也可以用类似数组下标的方法进行遍历。
for(int i = 0 ; i < 10 ; i ++) /*下标遍历*/
{
cout<< words[i] <<endl ;
}
接下来就是要按照我的既定思路,把每一行的字母按照大小写都存到一个数组里,这里在编译的时候遇到了一些麻烦,先看一下我一开始错误的写法:
char first[]={"Q","q","W","w","E","e","R","r","T","t","Y","y","U","u","I","i","O","o","P","p"};
这样写编译不通过,报错:初始化太多,我由于太渣,不明白什么叫初始化太多,百度半天才明白,是char []存的是一串字符串,比如char a[]=”012345”,虽然没有指明字符串的长度,但是此时系统已经开好了,就是大小为6—–‘0’ ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘\0‘;所以说我的初始化方法完全没脑子hhh
字符数组赋值后会自动在末尾加\0,所以定义数组最小长度长度需要比赋值长度大一,\0’是c/c++语言中的字符串结束符,在ASCII字符集中对应空字符NULL
字符数组有专门的的获取字符串实际长度的函数:strlen(a),该函数求得的是\0之前的字符个数。
另外插一句,看书的时候注意到,字符其实是一种特殊的整数,在ASCII编码表中,每一个字符都有一个整数编码,比如常用的应该要记住的,A-65,a-97,可以直接当整数用,比如int m=’a’-‘A’; m=32。
char *a 与char a[] 的区别
char *a = “hello” 中的a是指向第一个字符‘a’的一个指针
char a[20] = “hello” 中数组名a也是执行数组第一个字符‘h’的指针
但二者并不相同
char *m="777";
char s[10]="hello";
stract(m,s);
我们使用stract(a,b)(strcat(a,b)是把字符串a的结尾和字符串b的开始相连并存储于字符串a中)分别实现m+s和s+m
发现s+m是没问题的,因为数组是存放在栈中,是可以修改的。
而m+s就会报错,因为*m存放在常量区,是无法修改的。
所以,char *m只可以通过指针访问,无法修改。
回到之前的问题,其实
char * first[]={"Q","q","W","w","E","e","R","r","T","t","Y","y","U","u","I","i","O","o","P","p"};
也可以编译通过,char *first[]就是一个指针数组,可以存多个字符串。
差不多了,看一下我完整的很蠢的解法吧
- My Solution
class Solution {
public:
vector<string> findWords(vector<string>& words) {
string tmp,a,b,c,d;
int num[20000];
vector<string> output;
char first[21]="QWERTYUIOPqwertyuiop";
char second[21]="ASDFGHJKLasdfghjkl";
char third[21]="ZXCVBNMzxcvbnm";
int count=words.size();
for(int i=0;i<count;i++)
{
tmp=words[i];
for(int j=0;j<tmp.size();j++)
{
for(int k=0;k<20;k++)
{
a=tmp[j];
b=first[k];
c=second[k];
d=third[k];
if(a==b)
num[j]=1;
if(a==c)
num[j]=2;
if(a==d)
num[j]=3;
}
}
int m=0;
while(num[m]==num[0]&&m<tmp.size())
m++;
if(m==tmp.size())
output.push_back(tmp);
}
return output;
}
};
后面就是涉及到字符与字符相等的问题,只要==两边都是char或者string类型的字符,都是可以直接==的,当然也有一些比较函数,这里还是==最简单啦,其他的以后用到再说(又懒了)。
- Better Solution
class Solution {
public:
vector<string> findWords(vector<string>& words) {
vector<int> dict(26);
vector<string> rows = {"QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"};
for (int i = 0; i < rows.size(); i++) {
for (auto c : rows[i]) dict[c-'A'] = 1 << i;
}
vector<string> res;
for (auto w : words) {
int r = 7;
for (char c : w) {
r &= dict[toupper(c)-'A'];
if (r == 0) break;
}
if (r) res.push_back(w);
}
return res;
}
};
其中auto是C++11的新特性,主要有两种用途:自动类型推断和返回值占位
/*自动帮助推导类型*/
auto a = 10;
auto c = 'A';
auto s("hello");
for (auto c : rows[i])
这句,c的值其实就是rows[i]的枚举,表示rows[i]里的每一个值,似乎很好用的样子。
总体来说这个解法很取巧,用位运算,其实也没有简单多少,就是看上去很炫吧hhh
对了,就是toupper和tolower函数转换大小写还是很好用的,下次注意使用一下。