今天看到一个有意思的帖子,标题是“外包竟敢用vim,我一个正编都没敢用”。看得我不禁笑出声来,心想这位网友怕是对vim有点误解。
作为一名老程序员,我可以理解为什么新手看到vim会觉得头大。毕竟它那种模式化的编辑方式,起初确实让人迷惑不解。你一不小心按错一个键,屏幕上就满是各种让你心碎的乱码——这让我不禁想起我刚接触vim时的情景,那简直是血泪史。
但说实话,vim它的强大之处在于,经过一段时间的学习后,你会发现它的高效和灵活性简直让人上瘾。它没有鼠标这一“拖慢工作速度”的东西,整个编程过程变得非常流畅。我记得一开始也是不敢轻易用vim,怕出错怕崩溃。但随着时间的推移,你会渐渐习惯它的“心跳”,甚至离不开它。
老实说,外包用vim并不代表什么,反倒是能看出他们已经在追求更高效的工作方式了。如果你还在用传统的编辑器,不妨试试vim,换个角度看看编程的世界,或许会有意外的收获哦。
算法题:最大单词长度乘积
聊一个我觉得有点意思的算法题:最大单词长度乘积。你可能会想,这个题目听起来有点抽象,但其实如果理清楚思路,解决起来是相当直观的。
问题背景
题目大概的意思是,给你一个字符串数组,你需要找到两个单词,这两个单词必须是互不相交的(即它们的字符集没有任何重合),然后返回这两个单词长度的乘积。简单点说,就是你要找两个长度较大的单词,它们的字符完全不同。然后计算它们长度的乘积。
举个简单例子:
words = ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"]
这里面,“abcw”和“xtfn”是互不相交的两个单词,因为它们的字母集合没有重合,最大长度分别是4和4。所以它们的长度乘积就是16。
解决思路
如何高效地解决这个问题呢?我们可以通过位运算来简化判断单词字符集是否有重合。具体思路是:
通过位掩码(Bitmask)表示单词的字符集:我们可以用一个32位的整数来表示一个单词的字符集。假设字母是小写字母,那么每个字母就对应一个位置。例如,字母'a'对应的就是二进制的第0位,字母'b'对应第1位,依此类推。这样,对于一个单词,我们可以计算出它的掩码。
遍历所有单词:将每个单词转化为位掩码,并保存在一个数组中。
通过位运算判断是否有重合:对于每一对单词,我们用位运算“与(&)”来判断它们是否有共同的字符。如果结果为0,说明这两个单词没有字符重合,就可以计算它们的长度乘积。
代码实现
public class Solution {
public int maxProduct(String[] words) {
int n = words.length;
int[] bitMasks = new int[n];
// 将每个单词转换成位掩码
for (int i = 0; i < n; i++) {
int mask = 0;
for (char c : words[i].toCharArray()) {
mask |= 1 << (c - 'a'); // 设置字符对应位置为1
}
bitMasks[i] = mask;
}
int maxProduct = 0;
// 遍历所有单词对,判断是否有重合字符
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if ((bitMasks[i] & bitMasks[j]) == 0) { // 没有重合字符
maxProduct = Math.max(maxProduct, words[i].length() * words[j].length());
}
}
}
return maxProduct;
}
}
解释
位掩码的计算:对于每个单词,我们通过循环遍历每个字符,然后通过 1 << (c - 'a') 将对应的字母位置上的位设置为1。例如,字母'a'对应二进制的第0位,字母'b'对应第1位,依此类推。这样,我们就能将一个单词转化为一个整数,表示它的字符集。
位运算判断:当我们对两个单词的掩码做与(&)运算时,如果结果为0,说明它们没有重合的字符。这是因为没有重合的字符会导致位运算结果为0,表示两者的字符集合是独立的。
最大乘积的计算:每次当发现两个单词字符集没有重合时,我们就计算它们长度的乘积,并更新最大乘积。
时间复杂度
这个解法的时间复杂度主要来自两个部分:
转换单词为位掩码:我们需要遍历每个单词,并且每个单词最多有26个字母,所以这一部分的复杂度是 O(n * m),其中 n 是单词数量,m 是单词的最大长度。
检查所有单词对:我们需要检查每一对单词是否有字符重合。最坏情况下,检查所有单词对的复杂度是 O(n^2)。
因此,整体时间复杂度是 O(n^2),其中 n 是单词的数量。对于较小的输入,这个复杂度是完全可以接受的。
这个题目通过位运算的技巧,将一个看似复杂的字符比较问题转化成了整数的位运算问题,极大地提高了效率。通过这种方法,我们避免了直接比较两个单词中的每个字符,从而减少了不必要的计算。
当然了,如果你不习惯用位运算,也可以考虑其他的优化方式,但我觉得位运算这种思路对于这种问题来说是相当简洁高效的。至于结果,像这种题目就是那种“你做对了就能一口气做完,做错了也没办法后悔”的类型,所以我觉得能用位运算解决就挺爽的。