1832. 判断句子是否为全字母句
小目标:百篇题解之九,破百开源成库。关注我(Github、力扣),即可获取最新题解。
题目描述
全字母句 指包含英语字母表中每个字母至少一次的句子。
给你一个仅由小写英文字母组成的字符串 sentence
,请你判断 sentence
是否为 全字母句 。
如果是,返回 true
;否则,返回 false
。
示例 1:
输入:sentence = "thequickbrownfoxjumpsoverthelazydog" 输出:true 解释:sentence 包含英语字母表中每个字母至少一次。
示例 2:
输入:sentence = "leetcode" 输出:false
提示:
1 <= sentence.length <= 1000
sentence
由小写英语字母组成
相关信息:
- 难度:简单
- 标签:字符串
题解
此题是我在准备开始参加周赛之际在上一次周赛的虚拟竞赛中做的。虽然是虚拟竞赛,但是体验了一把,感觉还不错,能做出两道题目,对于我这算法菜鸡来说,真是莫大的鼓励。
这道题目主要的实现思路主要有两种:
- 遍历26个字母,判断其全都在 sentence 中。
- 遍历 sentence 所有字符,判断其是否包含全部26个字母。
由于 sentence 的长度是不定的,其范围在1到1000以内,所以我跟倾向于选择第一种思路来实现,这样可以减少遍历消耗。
方法一:ASCII 码+简单循环
由于题目中有说明是小写字母,故考虑使用 ASCII 码值来循环。此方法虽看起来简单,但是效率还是不错的,时间空间的消耗都超过了百分之九十。
/** * @param {string} sentence * @return {boolean} */ var checkIfPangram = function(sentence) { if(sentence.length<26)return false; //长度小于26,必然不是。 let isHave; for(let i=97;i<123;i++){ isHave=sentence.indexOf(String.fromCharCode(i)); //String.indexOf() 查找是否含有子串,成功返回子串开头的下标,失败返回-1 //String.fromCharCode() 将 ASCII 码值转换为对应的码值。 if(isHave==-1)return false; } return true; };
上边是我想到并实现的方法,很明显,它是前文所言的第一种实现思路。
下面还有许多奇妙的方法,都是从各种大佬的题解中学习到的一些方法,在此做个总结。我会贴出原代码以及写出我觉得可优化的提议并贴出优化后的代码:
方法二:转化为数组,并使用filter()去重
//原代码来自:https://leetcode-cn.com/problems/check-if-the-sentence-is-pangram/solution/js-by-mei-mei-xiang-xue-cyu-yan-a2me/ var checkIfPangram = function(sentence) { return (sentence.split('').filter(function(item, index, arr){ return arr.indexOf(item) === index; }).length)==26?true:false; };
这段代码首先使用 split() 方法将sentence转化为了字符数组,然后使用了filter() 来过滤重复字符,实现判断重复的最关键的是使用 indexOf() 方法,因为 indexOf() 始终返回的是从头至尾首次出现的元素的下标或者-1,倘若字符的下标和indexOf() 不符合,证明其不是首次出现。
这段代码,看代码形式是想写成一行代码解决的样子,但是其中有些写法稍微有点儿繁杂,主要有两点:
- filter的回调函数可以写成箭头函数形式,更简洁
- 最后的三元表达式没必要写,==返回值与所写的值是一样的。
//优化后的代码 var checkIfPangram = function (sentence) { return sentence.split('').filter((item, index, arr) => arr.indexOf(item) === index).length === 26 };
方法三:使用 Set 去重
前面方法二最关键的点便是去重,但其使用的是 filter 去重。这里用到了更高级的数据结构——Set,利用 Set 不能存储重复键值对的特性实现去重。
//原代码来自:https://leetcode-cn.com/problems/check-if-the-sentence-is-pangram/solution/js-qu-zhong-pai-xu-by-jingguangyan-yrjm/ var checkIfPangram = function(sentence) { if (sentence.length < 26) return false let arr = Array.from(new Set(sentence)) arr.sort() return arr.join('') === 'abcdefghijklmnopqrstuvwxyz' };
这段代码是先使用 Set 去重,然后使用 Array.from() 转化为数组,然后使用 Array.form() 排序,排序后再使用 join("") 连接成字符串并与'abcdefghijklmnopqrstuvwxyz'
比较。
这段代码的亮点是直接将 sentence 传入了 Set() 中做去重,但是在后续判断是否包含全部字母时的处理有些复杂,多了转数组,排序,然后转字符串并比较的过程。其实此时想要判断是否包含全部字母,只需要看 Set.size 属性值是否为 26 便好。因为题目的提示中有说 sentence 全部由小写字母构成,不会有其他字符哒。
//原代码来自:https://leetcode-cn.com/problems/check-if-the-sentence-is-pangram/solution/pan-duan-ju-zi-shi-fou-wei-quan-zi-mu-ju-pjrf/ var checkIfPangram = function(sentence) { var newSet = new Set(); for(var i = 0 ; i < sentence.length ; i++){ newSet.add(sentence[i]) } if(newSet.size==26){ return true }else{ return false } };
这段代码是先新建了一个 Set 对象 newSet,然后使用了一个 for 循环将每个字符添加到 newSet 中。最后判断长度是否等于26。
这段代码很简洁,很容易让人理解,不过还有两点可以优化的:
- 不必使用 for 循环,new Set() 可以直接传入一段字符串哒。当传入一段字符串时,它可以自动根据字符去重,且区分大小写,更详细的用法请参考MDN
- 最后这个if语句写得有些复杂了,完全可以用一个return语句替代
var checkIfPangram = function (sentence) { var newSet = new Set(sentence); return newSet.size === 26; };
再简单一步的话,可以直接写成一行代码解决形式:
var checkIfPangram = function (sentence) { return new Set(sentence).size === 26; };
方法四:利用 Map 去重
前面已经利用 filter 和 set 去重了,但其实 map 也能去重。What?不应该是 Set 吗?
//原代码来自:https://leetcode-cn.com/problems/check-if-the-sentence-is-pangram/solution/li-yong-mapqu-zhong-bing-jian-zhi-by-qyu-3dy1/ var checkIfPangram = function(sentence) { let map = new Map(), len = sentence.length; for(let i = 0; i < len; i++) { map.set(sentence[i]); //这里利用了map对象的key值不可重复的特性来达到去重的目的 if(map.size === 26) return true; } return false; };
很惊奇吧?觉得自己学了一个假的JS?我也是第一次看到这样的用法,日常中去重使用 Set 还是较多的,第一次看见有人使用 map 的 key 值不可重复的特性来达到去重的目的。这很极客~
但是我还是不太推荐这样的用法,毕竟这样的用法可读性较差,如果不是对 Map 所有属性极其了解,很难读懂这段代码,而且它的用法确实也不够规范。
我个人理解的更规范的用法应该如下:
var checkIfPangram = function (sentence) { let newMap = new Map(); for (let item of sentence) { if (!newMap.get(item)) { newMap.set(item, 1) //这个if的位置是个小细节 if (newMap.size === 26) return true; } } return false; };
上边代码中返回 true 的 if 判断是一个小细节,其实这个 if 不是一定要放在另一个 if 里面的,只是放在里面可以减少执行它的次数。因为 newMap.size 的值的改变都是在执行的set操作之后,这时候判断size值是最合适的,如果将其放在另一个 if 外,则每次循环都会进行判断,及时size值没有改变也会重复判断,这样就多余了。
以上就是本题的所有题解啦,感谢你能看到这里,如果本文对你有所帮助的话,别忘了给一个点赞三连嗷~
当然如果你对题解中的代码有不一样的优化意见,也欢迎你在评论区指出~
最重要的是不要忘了点点关注嗷(Github、力扣),以便获取我最新的题解以及文章通知。
github 结尾:
以上就是本题的所有题解啦,感谢你能看到这里,如果本文对你有所帮助的话,别忘了给一个 Star 嗷~
如果你对题解中的代码有不一样的优化意见,也欢迎你在 issue 中指出~
最重要的是不要忘了点点关注嗷(Github、力扣),以便获取我最新的题解以及文章通知。