纸上得来终觉浅,绝知此事要躬行。虽然通过《高程》学习了数组,字符串,正则表达式,但感觉还是流于表面,通过FCC的算法题可以很好地消化巩固这些知识。这里的答案首先是经过自己思考的,部分参考于stackover flow以及其他一些论坛,希望能为后来人留下一些指引。
题目链接:Check for Palindromes Complete
要求:检测字符是否是回文(指顺读和倒读都一样的词或短语,如refer),忽略大小写,空格,标点符号。
正则表达式这么写:/[^A-Za-z0–9]/g 或者 /[\W_]/g(正则表达式参考:《高程》、慕课网、regexper工具)
第一次写的时候直接用数组进行比较,发现虽然两个数组的内容是一样的,但是却不相等。
var reg = /[^a-zA-Z0-9]/g;
str.replace(reg,'').toLowerCase().split('')
//["m", "y", "a", "g", "e", "i", "s", "0", "0", "s", "i", "e", "g", "a", "y", "m"]
str.replace(reg,'').toLowerCase().split('').reverse()
//["m", "y", "a", "g", "e", "i", "s", "0", "0", "s", "i", "e", "g", "a", "y", "m"]
str.replace(reg,'').toLowerCase().split('') === str.replace(reg,'').toLowerCase().split('').reverse()
//false
这样的比较在对象上也行不通
var a = {name: "allen"}
//undefined
var b = {name: "allen"}
//undefined
a === b
//false
但在字符串上,这是行得通的
var s1='a'//undefined
var s2 = 'a'//undefined
s1 === s2//true
然后MDN看了Comparison operators:
比较操作符会为两个不同类型的操作数转换类型,然后进行严格比较。当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。
两个数组显然在栈中的引用是不一样的,比较的时候自然会返回false。和字符串基础类型不一样的是,如果使用的是构造函数构建字符串,哪怕内容相同两者也返回false。
var a = new String('foo');
var b = new String('foo');
a===b //false;
a == b //false;
于是去了stackoverflow看了下数组的比较,一种比较巧妙的是使用JSON.stringify()方法将数组化为JSON格式。
var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2); // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2)); // Returns true
所以答案出来了:
function palindrome(str) {
var reg = /[^a-zA-Z0-9]/g;
var origin = str.replace(reg,'').toLowerCase().split('');
var reverse = origin.reverse();
return JSON.stringify(origin) == JSON.stringify(reverse);
}
palindrome("eye");
palindrome("almostomla");
验证不通过。原因是sort()和reverse()两个方法都会改变原数组。修改的办法是先用slice(0)拷贝一个副本,这样就不会改变原来的数组了。
function palindrome(str) {
var reg = /[^a-zA-Z0-9]/g;
var origin = str.replace(reg,'').toLowerCase().split('');
var reverse = origin.slice().reverse();
return JSON.stringify(origin) == JSON.stringify(reverse);
}
palindrome("A man, a plan, a canal. Panama");
当然,上面的做法相对麻烦,适用于比较复杂的数组(比如元素是有许多属性的的对象),所以这里直接转化字符串比较很方便。
function palindrome(str) {
var re = /[\W_]/g;
var oldStr = str.toLowerCase().replace(re, '');
var reverseStr = oldStr.split('').reverse().join('');
return reverseStr === oldStr;
}
palindrome("A man, a plan, a canal. Panama");
这里的reverseStr还可以这样生成:
reverseStr = Array.prototype.map.call(oldStr, function(x) {
return x;
}).reverse().join('');
还有比较粗暴的方法是使用循环:
function palindrome(str) {
var re = /[^A-Za-z0-9]/g;
str = str.toLowerCase().replace(re, '');
var len = str.length;
for (var i = 0; i < len/2; i++) {
if (str[i] !== str[len - 1 - i]) {
return false;//只要有一个对应的位置不等就返回false
}
}
return true;//全部通过
}
palindrome("A man, a plan, a canal. Panama");