菜鸡前端一起学算法系列--第一天

写这些系列文章的初衷是因为面很多公司我都倒在了算法题上,一做算法题就感觉自己是个憨憨,所以要励精图治,吊打面试官,出这口恶气。
本人作者水的一批,所以从0开始学
算法题写了名字都是从leetcode上取得,可以通过标题搜到对应的题目。
没写名字都是我平时的时候遇到的
算法第一天:
复杂度的计算
O(1)
耗时和输入无关,例如访问对象属性
O(logn)
当数据增大n倍的时候,耗时增加logn(这里的log是以2为底的,比如,当数据增大256倍时,耗时只增大8倍,是比线性还要低的时间复杂度)。二分查找就是O(logn)的算法,每找一次排除一半的可能,256个数据中查找只要找8次就可以找到目标
二分查找算法如下:
function binary_search(arr, key) {
let low = 0;
let high = arr.length - 1;
while(low <= high) {
var mid = parseInt((high + low) / 2);
if(key == arr[mid]) {
return mid;
} else if (key > arr[mid]) {
low = mid + 1;
} else if (key < arr[mid]) {
high = mid - 1;
} else {
return -1;
}
}
return -1;
}
复制代码O(n)
就代表数据量增大几倍,耗时也增大几倍。比如常见的遍历算法
O(nlogn)
就是n乘以logn,当数据增大256倍时,耗时增大256*8=2048倍。这个复杂度高于线性低于平方。例如归并排序:
function mergeSort(arr) {
const len = arr.length;
if (len < 2) {
return arr;
}
let middle = Math.floor(len /2),
left = arr.slice(0, middle),
right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right))
}
function merge(left, right) {
const result = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift())
}
}
if(left.length) result.concat(left);
if(right.length) result.concat(right)
return result;
}
复制代码O(n^2)
就代表数据量增大n倍时,耗时增大n的平方倍,这是比线性更高的时间复杂度。比如冒泡排序,就是典型的O(n^2)的算法,对n个数排序,需要扫描n×n次
function sort(arr) {
const len = arr.length;
while(len–) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
}
}
}
}
复制代码各种数据结构js的表示

限制是仅允许在表的一端进行插入和删除运算,这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素
Class Stack {
constructor() {
this.values = []
}
add(val) {
this.values.push(val)
}
pop() {
this.values.pop();
}
}
复制代码链表
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
Class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
Class LinkList {
constructor() {
this.head = null;
this.length = 0;
}
add(value) {
const node = new Node(value);
if (this.head === null) {
this.head = node;
} else {
let currentNode = this.head;
while(currentNode.next) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
this.length++;
}
remove(element) {
let current = this.head;
let previous;
if (current === element) {
head = current.next;
} else {
while(current.value !== element) {
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.length–;
}
}
复制代码队列
Queue和Stack有一些类似,不同的是Stack是先进后出,而Queue是先进先出
Class Queue {
constructor() {
this.values = []
}
endequue(val) {
this.values.push(val)
}
dequeue() {
return this.values.shift()
}
}
复制代码集合
集合是数学中的一个基本概念,表示具有某种特性的对象汇总成的集体。在ES6中也引入了集合类型Set,Set和Array有一定程度的相似,不同的是Set中不允许出现重复的元素而且是无序的
class Set {
constructor() {
this.values = [];
}
add(val) {
if (!this.values.includes(val)) {
this.values.push(val)
return true;
}
return false;
}
remove(val) {
let index = this.values.findIndex(value => value === val)
if (index > -1) {
this.values.splice(index, 1)
return true;
}
return false;
}
}
复制代码树
Tree的数据结构和自然界中的树极其相似,有根、树枝、叶子

下面是树的实现:
class Node {
constructor(value, left, right) {
this.value = value;
this.left = left;
this.right = right;
}
}
Class Tree {
constructor() {
this.root = null
}
add(value) {
const Node = new Node(value);
function searchTree (node, val) {
if (val < node.value) {
if (node.left === null) {
node.left = Node;
} else {
searchTree(node.left)
}
} else {
if (node.right === null) {
node.right = Node;
} else {
searchTree(node.right);
}
}
}
if(this.root = null) {
this.root = Node;
return;
} else {
searchTree(this.root)
}
}
}
复制代码先学习这几样,太复杂的,估计一出我就不会了
compare-version-numbers
js版本,就是不足的用0的补齐
function compare(a, b) {
let n1 = parseInt(a, 10);
let n2 = parseInt(b, 10);
if (n1 > n2) {
return 1;
} else if (n1 < n2) {
return -1;
} else {
return 0;
}
}

var compareVersion = function(version1, version2) {
let m = version1.split(’.’);
let n = version2.split(’.’);
let i = 0;
let j = 0;
while(i < m.length || j < n.length) {
let a, b;
a = i < m.length ? m[i] : ‘0’;
b = j < n.length ? n[j] : ‘0’;
let res = compare(a, b);
if (res === 0) {
i++;
j++;
} else {
return res;
}

}
return 0;
};
复制代码知道大于某个数的值的个数
提供一个有序数组,然后找到小于这个数的个数
[1, 2, 3, 4]
2
// 1
复制代码下面是我的代码,采用二分算法,但是需要计算之前的数字
function find(arr, val) {
let sum = 0;
let index = Math.floor(arr.length / 2);
let center = arr[index];
while(arr.length > 0) {
if (center < val) {
sum += index + 1;
if (arr[index + 1] < val) {
arr = arr.splice(index + 1)
index = Math.floor(arr.length / 2);
center = arr[index];
} else {
return sum;
}
} else {
arr = arr.splice(0, index);
index = Math.floor(arr.length / 2);
center = arr[index];
}
}
return sum;
}
复制代码letter-combinations-of-a-phone-number
这道题有毒,我用执行代码就能通过,但是一提交就不行

先提供一个映射表
确定前面的可能,在和后面的组合

const map = {
2: [‘a’, ‘b’, ‘c’],
3: [‘d’, ‘e’, ‘f’],
4: [‘g’, ‘h’, ‘i’],
5: [‘j’, ‘k’, ‘l’],
6: [‘m’, ‘n’, ‘o’],
7: [‘p’, ‘q’, ‘r’, ‘s’],
8: [‘t’, ‘u’, ‘v’],
9: [‘w’, ‘x’, ‘y’, ‘z’]
}
var list = [];

function traceBack(front, letters) {
if (letters.length == 0) {
list.push(front);
return false;
}
const firstStr = letters.substring(0, 1);
const codeArr = map[firstStr];
for (let i = 0; i < codeArr.length; i++) {
traceBack(front + codeArr[i], letters.substring(1))
}
}
var letterCombinations = function (digits) {
if (digits.length > 0) {
traceBack(’’, digits);
return list;
} else {
return []
}
};
复制代码happy-number
如果是快手数,那么生成值不会重复
function auxiliary(num) {
let last = 0;
while (num > 0) {
const current = num % 10;
last += current ** 2;
num = Math.floor(num / 10);
}
return last;
}
var isHappy = function(n) {
let set = new Set();
while (n !== 1) {
n = auxiliary(n);
if (!set.has(n)) {
set.add(n);
} else {
return false;
}
}
return true;
};

发布了60 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/a59612/article/details/104406472