题目来源:leetcode
题目描述:
实现一个算法,确定一个字符串 s 的所有字符是否全都不同。
题解:
看到问题,第一反应是使用循环+新建map数据结构进行解答,代码如下
解法1:
var isUnique = function(astr) { // 思路1 let isAllSame = true; const strMap = {} for(let i of astr) { if(strMap[i]) { strMap[i] += 1 } else { strMap[i] = 1 } } for(let k in strMap) { if(strMap[k] > 1) { isAllSame = false; break; } }}
时间复杂度:O(n)
空间复杂度:O(n)
思考过后,其实这里map可以替换成Set数据结构,大致思路也是如此,就不多写了。
那能不能不新建新的数据解构呢?
解法2:循环嵌套
// 思路2 for(let i = 0 ; i < astr.length; i++) { for(let j = i + 1; j < astr.length; j++) { if(astr[i] === astr[j]) { return false } } }
时间复杂度:O(n2)
空间复杂度:O(1)
上面的步骤虽然不需要新建数据结构,但是时间复杂度还是不友好,有没有更友好的方式呢?
解法3:位运算
let bitMask = 0; for(let i of astr) { let move_bit = i.charCodeAt(0) - 'a'.charCodeAt(0) let charBit = 1 << move_bit if((charBit & bitMask) > 0) { return false } bitMask |= charBit }
return true
题解分析:
Js位运算介绍可参考:按位与
题目告诉我们,这里都是字符串,并且都是小写字母,总共26个,那我们能不能创建一个26位的数字,00...01,从低位到高位每一个位置分别代表一个字母,如果字符串中出现了字母,就把对应位置上的值改为1;
如字符串a,对应的数字为:00....1;字符串b,对应的数字为:00....10
如果字符串中某个字母出现了多次,那对应的两个数字做与运算,一定大于0;
反之,如果字符串中所有的字母都只出现了依次,那与运算的结果,一定是0;
好,按照上面的说法,有三个问题要解决。
问题1:如果用0000..1表示a,0000..10表示b,如果有26个字母,我岂不是要建一个map表,然后再一一对应获取?
这样太麻烦了,太不优雅了吧?
怎么办?
位移运算由此而生:位移
我们发现,如果用阿拉伯数字1表示a,2表示b,它们之间的相差1;
相应的,只需要把0000..1左位移1,是不是就得到了0000..10。
惊喜!!!
也就是说我们只需要得到当前字母相相对于a的编码差,就能够获取到对应的位运算数值了。
Js中获取编码的方式
let move_bit = i.charCodeAt(0) - 'a'.charCodeAt(0)
let charBit = 1 << move_bit
**问题2:**与运算的左右应该是什么?
左边我们知道,是当前字母对应的位数值,那右边呢?
右边应该是当前字母之前的所有字母的位数值表达?
那问题来了,如何获取。
首先想到的是循环,对字符串进行循环
for(let i of astr) {}
循环体中做什么呢?
或运算应运而生。
根据或运算特性,如字符串abc
第一个字母a,表示为000...1
第二个字母b,表示为00...10
那000...1 | 00...10 = 00...11,完美。
所以,我们可以在循环体的末尾,对当前字母位运算值和之前所有字母的位运算值做或运算。
bitMask |= charBit
问题3:如何判断是否重复?
经过上线的分析,我们就好判断了,也就是终极武器:与运算。
如果字符串为aa,那也就是000..1 & 000..1,结果一定是大于0的;
如果字符串为ab,那也就是000..1 & 00..10,结果一定是等于0的;
所以,只需要通过与运算进行判断即可,
if((charBit & bitMask) > 0) { return false }
综上,全部的代码为:
let bitMask = 0;
for(let i of astr) {
let move_bit = i.charCodeAt(0) - 'a'.charCodeAt(0)
let charBit = 1 << move_bit
if((charBit & bitMask) > 0) {
return false
}
bitMask |= charBit
}
return true
时间复杂度:O(n)
空间复杂度:O(1)