题目描述:
给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。
美式键盘 中:
第一行由字符 "qwertyuiop" 组成。
第二行由字符 "asdfghjkl" 组成。
第三行由字符 "zxcvbnm" 组成。
提示:
- 1 <= words.length <= 20
- 1 <= words[i].length <= 100
- words[i] 由英文字母(小写和大写字母)组成
解法:
本题比较简单,但要追求效率。
考虑判断一个字符串是否可以“一行打出”。先考虑字符串的第一个字符,根据它属于哪一行将标记变量 focus 设置为对应的行号(取值在1、2、3)。然后遍历之后的字符,如果出现一个字符属于的行与 focus 变量设置的标记不同,则将标记变量 flag 置为 0,表示此字符串不能“一行打出”,退出遍历。如果遍历结束后 flag 任然为 1,则表示此字符串可以“一行打出”。
代码如下:
#include <stdio.h>
#include <stdlib.h>
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
char charIn(char c, char * cs, int n){
int i;
if(c <= 'Z')
c += 32;
for(i=0; i<n; i++)
if(c == cs[i])
return 1;
return 0;
}
char ** findWords(char ** words, int wordsSize, int* returnSize){
char l1[] = "qwertyuiop";
char l2[] = "asdfghjkl";
char l3[] = "zxcvbnm";
char ** ret = (char **) malloc(wordsSize * sizeof(char *));
* returnSize = 0;
int i, j, focus, flag;
for(i=0; i<wordsSize; i++){
j = 0;
flag = 1; // 表示可以由一行打出
while(words[i][j] != '\0'){
if(j == 0){
if(charIn(words[i][0], l3, 7))
focus = 3;
else if(charIn(words[i][0], l2, 9))
focus = 2;
else
focus = 1;
}else{
if(focus == 1 && !charIn(words[i][j], l1, 10)){
flag = 0;
break;
}else if(focus == 2 && !charIn(words[i][j], l2, 9)){
flag = 0;
break;
}else if(focus == 3 && !charIn(words[i][j], l3, 7)){
flag = 0;
break;
}
}
j++;
}
// 根据题目条件,不用考虑空串
if(flag)
ret[(*returnSize)++] = words[i];
}
return ret;
}
结果如下,可以看到性能不错。