所以这是下面的问题,以及我的回答。我知道由于双嵌套的for循环,效率为O(n ^ 2),所以我想知道是否有一种方法可以改善算法/函数的大O。
//设计一种算法并编写代码以删除字符串中的重复字符,而无需使用任何其他缓冲区。注意:一个或两个其他变量都可以。不是数组的额外副本。
function removeDuplicates(str) {
let arrayString = str.split("");
let alphabetArray = [["a", 0],["b",0],["c",0],["d",0],["e",0],["f",0],["g",0],["h",0],["i",0],["j",0],["k",0],["l",0],["m",0],["n",0],["o",0],["p",0],["q",0],["r",0],["s",0],["t",0],["u",0],["v",0],["w",0],["x",0],["y",0],["z",0]]
for (let i=0; i<arrayString.length; i++) {
findCharacter(arrayString[i].toLowerCase(), alphabetArray);
}
removeCharacter(arrayString, alphabetArray);
};
function findCharacter(character, array) {
for (let i=0; i<array.length; i++) {
if (array[i][0] === character) {
array[i][1]++;
}
}
}
function removeCharacter(arrString, arrAlphabet) {
let finalString = "";
for (let i=0; i<arrString.length; i++) {
for (let j=0; j<arrAlphabet.length; j++) {
if (arrAlphabet[j][1] < 2 && arrString[i].toLowerCase() == arrAlphabet[j][0]) {
finalString += arrString[i]
}
}
}
console.log("The string with removed duplicates is:", finalString)
}
removeDuplicates("Hippotamuus")
答案 0 :(得分:1)
相同大小写的所有字母的ASCII / Unicode字符代码是连续的。这允许进行重要的优化:您可以从字符计数数组的ASCII / Unicode字符代码中找到该字符的索引。具体来说,字符计数数组中字符c
的索引将为c.charCodeAt(0) - 'a'.charCodeAt(0)
。这样一来,您就可以在O(1)
时间内查找和修改数组中的字符数,从而将算法运行时间缩短至O(n)
。
答案 1 :(得分:1)
根据您的描述,我假设输入是字符串(在javascript中是不可变的),并且我不确定“一个或两个其他变量” 的确切含义是什么,在您的实现中,我将假设可以使用O(N)空间。为了提高时间复杂度,我认为实现方法会根据输出字符串的不同要求而有所不同。
假设s的长度为N,以下实现使用O(N)空间和O(N)时间。
function removeDuplicates(s) {
const set = new Set(); // use set so that insertion and lookup time is o(1)
let res = "";
for (let i = 0; i < s.length; i++) {
if (!set.has(s[i])) {
set.add(s[i]);
res += s[i];
}
}
return res;
}
您可以使用快速排序进行就地排序,然后循环遍历已排序的数组以将最后看到的元素添加到结果中。请注意,您可能需要先将字符串拆分为一个数组。因此该实现将使用O(N)空间,平均时间复杂度为O(NlogN)
以下实现使用O(N)空间和O(N)时间。
const removeDuplicates = function(s) {
const stack = []; // stack and set are in sync
const set = new Set(); // use set to make lookup faster
const lastPos = getLastPos(s);
let curVal;
let lastOnStack;
for (let i = 0; i < s.length; i++) {
curVal = s[i];
if (!set.has(curVal)) {
while(stack.length > 0 && stack[stack.length - 1] > curVal && lastPos[stack[stack.length - 1]] > i) {
set.delete(stack[stack.length - 1]);
stack.pop();
}
set.add(curVal);
stack.push(curVal);
}
}
return stack.join('');
};
const getLastPos = (s) => {
// get the last index of each unique character
const lastPosMap = {};
for (let i = 0; i < s.length; i++) {
lastPosMap[s[i]] = i;
}
return lastPosMap;
}
答案 2 :(得分:1)
有一个小技巧“不使用任何额外的缓冲区”,尽管我没有找到一种方法来提高beforeEach(() => {
fixture = TestBed.createComponent(Component);
component = fixture.componentInstance;
service = fixture.debugElement.injector.get(Service);
});
it('should get a subscription event', () => {
const response: any[] = [];
service.observer$ = new Subject<any>();
fixture.detectChanges();
service.observer$.next(['some content']);
expect(component.x.length).toBeGreaterThan(0);
});
的复杂性,而无需使用散列图来确定是否已看到特定字符。诀窍是遍历输入字符串缓冲区(假定它是一个JavaScript数组,因为JavaScript中的字符串是不可变的),如果当前字符重复,则用下一个唯一字符覆盖当前字符。最后,用空字符标记结果字符串的结尾。
伪代码:
O(n^2)
如果我们使用哈希映射,则函数i = 1
pointer = 1
while string[i]:
if not seen(string[i]):
string[pointer] = string[i]
pointer = pointer + 1
i = i + 1
mark string end at pointer
可能占用seen
时间和O(n)
空间或O(1)
时间和O(1)
空间。
答案 3 :(得分:1)
我不确定这是什么意思
...不使用任何其他缓冲区。
所以我想我可以一口气做到这一点,让你告诉我是否有错。
我所做的工作是,您提供的功能可以提供正确的输出,而您只是在寻找运行速度更快的功能。下面的函数可以提供正确的输出,并且在处理任何带有大量重复项的大型字符串时,运行速度都快得多。
function removeDuplicates(originalString) {
let outputString = '';
let lastChar = '';
let lastCharOccurences = 1;
for (let char = 0; char < originalString.length; char++) {
outputString += originalString[char];
if (lastChar === originalString[char]) {
lastCharOccurences++;
continue;
}
if (lastCharOccurences > 1) {
outputString = outputString.slice(0, outputString.length - (lastCharOccurences + 1)) + originalString[char];
lastCharOccurences = 1;
}
lastChar = originalString[char];
}
console.log("The string with removed duplicates is:", outputString)
}
removeDuplicates("Hippotamuus")
再次,抱歉,如果我误解了该帖子...