LC_training(3)
quickSort 会写递归版本, partition不开新空间. nlogn, logn(只考虑算法运行空间,但是n个元素必然需要n的空间)
mergeSort 会写递归版本, merge需要新空间, nlogn, n+logn;
mergeSort 会写迭代版本, merge需要新空间, nlogn, n;
手写快排()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25function quickSort(arr, left, right) {
var len = arr.length,
partitionIndex,
left = typeof left != 'number' ? 0 : left,
right = typeof right != 'number' ? len - 1 : right;
if (left < right) {
partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex-1);
quickSort(arr, partitionIndex+1, right);
}
return arr;
}
function partition(arr, left ,right) { // 分区操作
var pivot = left, // 设定基准值(pivot)
index = pivot + 1;
for (var i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index-1;
}时间复杂度: nlogn, 空间复杂度: logn (递归的压栈导致)
mergeSort的递归和迭代
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var mergeSortArr = function(arr) {
if(arr.length == 1) return arr;
let mid = Math.floor(arr.length/2);
return myMerge(mergeSort(arr.slice(0,mid)), mergeSort(arr.slice(mid,arr.length)));
}
//trick of array operation
var myMergeArr = function(arr1,arr2){
let res =[];
while(arr1.length>0&&arr2.length>0){
if(arr1[0]<arr2[0]){
res.push(arr1.shift());
} else {
res.push(arr2.shift());
}
}
return res.concat(arr1).concat(arr2);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31var mergeSortArrIterate = function(arr) {
let step = 1;
for(step = 1; step<arr.length;step = step<<1){
let left = 0,right = left+step;
while(right+step<arr.length){
myMergeArr_ChangeFormer(arr, left,left+step,right,right+step)
left = right+step;
right = left+step;
}
if(right<arr.length){
myMergeArr_ChangeFormer(arr, left,left+step,right,arr.length);
}
}
return arr;
}
var myMergeArr_ChangeFormer = function(arr,lb,le,rb,re){
let res =[];
let arr1 = arr.slice(lb,le);
let arr2 = arr.slice(rb,re);
while(arr1.length>0&&arr2.length>0){
if(arr1[0]<arr2[0]){
res.push(arr1.shift());
} else {
res.push(arr2.shift());
}
}
res = res.concat(arr1).concat(arr2);
for (i=lb;res.length;i++){
arr[i] = res.shift();
}
}
链表的翻转
1
2
3
4
5
6
7
8
9
10
11
12var reverseListIterate = function(head) {
let currNode = head;
let resHead = null;
let tmp = null;
while(currNode){
tmp = currNode.next;
currNode.next = resHead;
resHead = currNode;
currNode = tmp;
}
return resHead;
}最重要的是不要忘了链表的头插法
快速找到链表的二分结点: 快慢指针
因为指针走到最后时, 已经忘记了mid在何处.
1
2
3
4
5
6
7
8var findMidNode = function(head){
let p1 = p2 =head;
while(p2&&p2.next){
p2 = p2.next.next;
p1 = p1.next;
}
return p1;
}concat()
方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。1
2
3
4
5
6const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);
console.log(array3);
// expected output: Array ["a", "b", "c", "d", "e", "f"]slice()
方法返回一个新的数组对象,这一对象是一个由begin
和end
决定的原数组的浅拷贝(包括begin
,不包括end
)。原始数组不会被改变。1
2
3
4
5
6
7const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]array的这个merge写的太好了, 不得不看:
1
2
3
4
5
6
7
8
9
10
11var myMergeArr = function(arr1,arr2){
let res =[];
while(arr1.length>0&&arr2.length>0){
if(arr1[0]<arr2[0]){
res.push(arr1.shift()); //巧妙地利用shift,减少了指针的遍历
} else {
res.push(arr2.shift());
}
}
return res.concat(arr1).concat(arr2);//假如一个为空,也无所谓
}