我试图创建一个旨在递归消除数组中任何连续重复元素的函数。它与全局变量一起使用,但是,我发现解决此问题的能力较弱。我的代码基于此code(从字符串中删除所有连续的重复项;使用的语言:C ++)。我知道字符串和数组之间存在可变性差异,但是我不完全了解后台堆栈发生了什么。函数运行后,全局变量正确,但是函数本身的输出却不正确。任何解释或指示将不胜感激。谢谢!
这不是作业问题,我只是想将递归锤入我的头骨,因为它仍然使我陷入困境。双关语很抱歉。
//var testArr = [1, 1, 2, 2, 3, 3, 1, 1, 1]
//compress(testArr); //[1,2,3,1] //<= expected result
//current output [1, 2, 2, 3, 3, 1, 1, 1]
var arr = [];
var compress = function(list) {
//var arr = [];
if (list.length === 0) {
return arr;
}
if (list.length === 1) {
arr.push(list[0]);
return list
}
if (list.length > 1 && list[0] !== list[1]) {
arr.push(list[0])
compress(list.slice(1,));
}
if (list.length > 1 && list[0] === list[1]) {
list.splice(0,1);
compress(list);
}
return list;
}
答案 0 :(得分:2)
因为list.slice(1,)
复制了数组,所以在递归调用中list
不是原始数组。进行更改不会更改原始数组。您必须更改要返回的列表(将结果传递到调用堆栈中):
list = [list[0], ...compress(list.slice(1,))];
也许更短:
const compress = arr => arr.length > 1
? arr[0] === arr[1]
? compress(arr.slice(1))
: [arr[0], ...compress(arr.slice(1))]
: arr;
答案 1 :(得分:2)
基本上,您需要返回arr
而不是list
。
然后,您需要检查一下实际元素的不等价,然后下一个元素进行推送。
继续使用切片数组,最后返回arr
。
var arr = [];
var compress = function(list) {
if (list.length === 0) {
return arr;
}
if (list.length === 1) {
arr.push(list[0]);
return arr;
}
if (list[0] !== list[1]) {
arr.push(list[0])
}
return compress(list.slice(1));
};
console.log(compress([1, 1, 2, 2, 3, 3, 1, 1, 1]));
另一种方法是直接在函数中使用arr
,这里重命名为result
。
此代码经过了优化,因为在有更多项目的情况下,它以对递归函数的调用结束。
var compress = function(list, result = []) {
if (list.length === 0) {
return result;
}
if (list.length === 1) {
result.push(list[0]);
return result;
}
if (list[0] !== list[1]) {
result.push(list[0])
}
return compress(list.slice(1), result);
};
console.log(compress([1, 1, 2, 2, 3, 3, 1, 1, 1]));
一种更短的方法,无需使用其他数组作为结果。
var compress = function(list) {
return list.length
? [].concat(list[0] === list[1] ? [] : list[0], compress(list.slice(1)))
: [];
};
console.log(compress([1, 1, 2, 2, 3, 3, 1, 1, 1]));
答案 2 :(得分:2)
您可以通过在列表的尾部进行递归来进行经典的递归(类似于Haskell),而无需使用全局变量:
var compress = function(list) {
if (list.length === 0) return [];
let [head, ...rest] = list
let l = compress(rest)
return (l[0] === head)
? l
: [head, ...l]
}
var testArr = [1, 1, 1, 1, 2, 2, 3, 3, 1, 1, 1, 2, 2]
console.log(compress(testArr))
答案 3 :(得分:2)
使用ECMAScript 6功能:
const testArr = [1, 1, 2, 2, 3, 3, 1, 1, 1];
const compress = ([head, ...rest]) => {
if (!head) return [];
const tail = compress(rest);
return head === tail[0] ? tail : [head, ...tail];
}
console.log(compress(testArr));
作为旁注,我想指出功能方法要短一些(是的,我知道问题在于递归方法):
const testArr = [1, 1, 2, 2, 3, 3, 1, 1, 1];
const output = testArr.reduce((list, next) => list.slice(-1)[0] === next ? list : [...list, next], []);
console.log(output);
答案 4 :(得分:1)
首先,您需要确定基本情况,即数组的长度小于2的情况。递归部分需要根据没有连续重复项的条件来决定返回数组的外观。
function compress(list) {
if (list.length <= 1) {
return list //base case
} else if (list[0] === list[1]) {
return compress(list.slice(1, )) //discard head of list
} else {
return [list.shift()].concat(compress(list)) //keep head
}
}
console.log(compress([1,2,2,3,3,2,3,3,3,3])) //[1,2,3,2,3]
console.log(compress([2])) //[2]
console.log(compress([])) //[]
答案 5 :(得分:0)
尚不清楚您是否打算修改原始输入。使用slice
会产生一个副本以传递到下一个函数调用,但是调用splice
确实会修改原始输入,与链接到的C ++代码一样。听起来好像您想摆脱全局变量,所以让我们开始吧。
这里有两个版本。使用JavaScript进行动态参数分配很方便,这意味着我们可以只用一个参数进行第一个函数调用,但可以设置一个默认的第二个参数,然后在递归过程中进行引用。
此版本非常简单。它通过向后遍历并删除多余的元素来修改原始输入,这也可以简单地通过循环来完成。这个版本使用O(n)
时间,没有多余的空间。
// Our parameters are the original list and an
// index, i, pointing to our current array cell.
// We default to starting at the end of the list,
// can you think why? (Hint: think what would happen
// after our call to 'splice' if we went forward)
var compress = function(list, i = list.length - 1) {
// Base case, we've reached the beginning
// of the list so we're done, return the
// modified list
if (i == 0)
return list;
// The current element is the same as
// the next one we're going to look at
// (that's the one at i - 1) so remove it!
if (list[i] == list[i - 1])
list.splice(i, 1);
// Return the result of continuing
// each element's examination
return compress(list, i - 1);
}
console.log(compress([1, 1, 2, 2, 3, 3, 1, 1, 1]));
这是一个不会修改原始列表的版本,并且(与此处的其他答案类似)通过在每个递归调用上创建列表尾部的副本,从而导致O(n^2)
空间使用情况(以及时间) :
var compress = function(list) {
// The list is not long enough
// to have extra elements, return it.
if (list.length < 2)
return list
// The first two elements are different
// so we definitely want to keep the
// first one. Let's place it in an array
// that we will 'concat' with the result
// of compressing the list tail (the rest of the list).
if (list[0] != list[1])
return [list[0]].concat(compress(list.slice(1)));
// If we got here, the first two elements
// are similar so we definitely just want
// the result of compressing the rest of the list.
return compress(list.slice(1));
}
console.log(compress([1, 1, 2, 2, 3, 3, 1, 1, 1]));