JavaScript Anagram 函数的时间复杂度
Time Complexity for JavaScript Anagram Function
我有一个分配给一个函数的权利,该函数将接受 2 个字符串和 return 需要删除的字符数,以使这 2 个字符串彼此变位。我的问题是这个函数的时间复杂度是多少,是否有更快的方法来达到相同的结果。
这是我的解决方案:
function anagramDelete(str1, str2){
let obj1 = {}, obj2 = {};
// Load obj1 with all characters of str1 and their count
str1.split('').forEach((char)=> {
if(char in obj1){
obj1[char]++;
} else {
obj1[char] = 1;
}
});
// Load obj2 with all characters of str1 and their count
str2.split('').forEach((char)=> {
if(char in obj2){
obj2[char]++;
} else {
obj2[char] = 1;
}
});
// Track # of chars deleted
let numOfDeletions = 0;
// Compare each char in obj1 w obj2 and count deletions
for(char in obj1){
if(obj2[char]){
numOfDeletions += Math.abs(obj2[char] - obj1[char]);
} else {
numOfDeletions += obj1[char];
}
}
// Compare each char in obj2 w obj1 and count deletions
for(char in obj2){
if(!obj1[char]){
numOfDeletions += obj2[char];
}
}
return numOfDeletions;
}
据我所知,因为有 4 个循环,所以它是 O(4n) 或只是 O(n)。我这样说是因为没有嵌套循环。这个对吗?有更好的解决方案吗?
您可以使用单个对象并仅对绝对值求和。
此解决方案将字符串用作类似于对象的数组。
function anagramDelete(str1, str2) {
var letters = {};
Array.prototype.forEach.call(str1, char => letters[char] = (letters[char] || 0) + 1);
Array.prototype.forEach.call(str2, char => letters[char] = (letters[char] || 0) - 1);
return Object.keys(letters).reduce((r, k) => r + Math.abs(letters[k]), 0);
}
console.log(anagramDelete('anagram', 'function'));
不是更好而是更短:
function anagramDelete(str1, str2){
const chars = {};
var result = 0;
for(const char of str1)
chars[char] = (chars[char] || 0) +1;
for(const char of str2)
chars[char] = (chars[char] || 0) -1;
for(const [char, count] of Object.entries(chars))
result += Math.abs(count);
return result;
}
您的密码是O(n + m)
;一般来说,人们并不太关心复杂度 class 中的常量。 n
是第一个字符串的长度,m
是第二个字符串的长度。
还有:
准确地说,因为你提到了 O(4n)
- 我不确定这是否准确。您使用 split
函数两次,在您的情况下将字符串转换为字符数组。您在分析中没有考虑到这一点。
O(n + m)
将是正确答案。
如果您想详细分析,那就是 O(3n + 3m)
。那是因为:
- 对于您使用的第一个字符串 split
(O(n)
),您遍历每个字符 (O(n)
) 并再次循环进行比较 (O(n)
)
- 对于使用 split
(O(m)
) 的第二个字符串,循环遍历每个字符 (O(m)
) 并再次循环进行比较 (O(m)
)
我假设你的代码是正确的。我没有检查。
P.S.:
如果您对微调常量感兴趣,可以参考其他答案,理论上它们可能比您的代码更快。实际上,我认为这并不重要。
我有一个分配给一个函数的权利,该函数将接受 2 个字符串和 return 需要删除的字符数,以使这 2 个字符串彼此变位。我的问题是这个函数的时间复杂度是多少,是否有更快的方法来达到相同的结果。 这是我的解决方案:
function anagramDelete(str1, str2){
let obj1 = {}, obj2 = {};
// Load obj1 with all characters of str1 and their count
str1.split('').forEach((char)=> {
if(char in obj1){
obj1[char]++;
} else {
obj1[char] = 1;
}
});
// Load obj2 with all characters of str1 and their count
str2.split('').forEach((char)=> {
if(char in obj2){
obj2[char]++;
} else {
obj2[char] = 1;
}
});
// Track # of chars deleted
let numOfDeletions = 0;
// Compare each char in obj1 w obj2 and count deletions
for(char in obj1){
if(obj2[char]){
numOfDeletions += Math.abs(obj2[char] - obj1[char]);
} else {
numOfDeletions += obj1[char];
}
}
// Compare each char in obj2 w obj1 and count deletions
for(char in obj2){
if(!obj1[char]){
numOfDeletions += obj2[char];
}
}
return numOfDeletions;
}
据我所知,因为有 4 个循环,所以它是 O(4n) 或只是 O(n)。我这样说是因为没有嵌套循环。这个对吗?有更好的解决方案吗?
您可以使用单个对象并仅对绝对值求和。
此解决方案将字符串用作类似于对象的数组。
function anagramDelete(str1, str2) {
var letters = {};
Array.prototype.forEach.call(str1, char => letters[char] = (letters[char] || 0) + 1);
Array.prototype.forEach.call(str2, char => letters[char] = (letters[char] || 0) - 1);
return Object.keys(letters).reduce((r, k) => r + Math.abs(letters[k]), 0);
}
console.log(anagramDelete('anagram', 'function'));
不是更好而是更短:
function anagramDelete(str1, str2){
const chars = {};
var result = 0;
for(const char of str1)
chars[char] = (chars[char] || 0) +1;
for(const char of str2)
chars[char] = (chars[char] || 0) -1;
for(const [char, count] of Object.entries(chars))
result += Math.abs(count);
return result;
}
您的密码是O(n + m)
;一般来说,人们并不太关心复杂度 class 中的常量。 n
是第一个字符串的长度,m
是第二个字符串的长度。
还有:
准确地说,因为你提到了 O(4n)
- 我不确定这是否准确。您使用 split
函数两次,在您的情况下将字符串转换为字符数组。您在分析中没有考虑到这一点。
O(n + m)
将是正确答案。
如果您想详细分析,那就是 O(3n + 3m)
。那是因为:
- 对于您使用的第一个字符串 split
(O(n)
),您遍历每个字符 (O(n)
) 并再次循环进行比较 (O(n)
)
- 对于使用 split
(O(m)
) 的第二个字符串,循环遍历每个字符 (O(m)
) 并再次循环进行比较 (O(m)
)
我假设你的代码是正确的。我没有检查。
P.S.:
如果您对微调常量感兴趣,可以参考其他答案,理论上它们可能比您的代码更快。实际上,我认为这并不重要。