一、排序(參考)
一定要熟悉各個排序的時間複雜度
1、冒泡排序
兩層循環,外層控制趟數,內層兩兩比價
function sort(arr){
var len = arr.length;
for(let i = len-1; i >= 2 ; i--){
for(let j = 0 ; j < len; j++){
if(arr[j]>arr[j+1]){
let temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp;
}
}
return arr
}
//優化,使用es6的賦值結構
function sort(arr){
var len = arr.length;
for(let i = len-1; i >= 2 ; i--){
for(let j = 0 ; j < len; j++){
if(arr[j]>arr[j+1]){
[arr[j],arr[j+1]] = [arr[j+1],arr[j]]
}
}
return arr
}
2、選擇排序
從數組的開頭開始,將第一個元素和其他元素作比較,檢查完所有的元素後,最小的放在第一個位置,接下來再開始從第二個元素開始,重複以上一直到最後。
function sort(arr){
var len = arr.length;
for(let i = 0 ; i <len-1 ; i++){
for( j = i ; j < len ; j++){
if(arr[j] <arr [i]){
[arr[i],arr[j]] = [arr[j],arr[i]]
}
}
}
retrun arr
}
3、插入排序
首先將待排序的第一個記錄作爲一個有序段
從第二個開始,到最後一個,依次和前面的有序段進行比較,確定插入位置
function insertsort(arr){
var len = arr.length
for(let i = 1 ; i < len ; i++ )//默認arr[0]有序
{
for(let j = i ; j > 0 ; j--){
if(arr[j]>arr[j-1){
break;
}
else{
[arr[j-1],arr[j]] = [arr[j],arr[j-1]]
}
}
}
return arr
}
4、快排
它是一種分而治之的算法,通過遞歸的方式將數據依次分解爲包含較小元素和較大元素的不同子序列。該算法不斷重複這個步驟直至所有數據都是有序的。
function quicksort(arr){
if(arr.length <= 1) {
return arr; //遞歸出口
}
var len = arr.length;
var left = [],
var right = []
var current = arr.splice(0,1)
for(let i = 0 ; i < len -1 ; i++){
if(arr[i]>current){
right.push(arr[i])
}else{
left.push(arr[i])
}
}
//遞歸
return quicksort(left).concat(current,quicksort(right))
}
5、桶排序
const list = [8, 3, 5, 9, 2, 3, 0, 8]; // 待排序數組
/**
* params {number[]} list
* return {number[]}
*/
function sort(list) {
const newList = Array.from({length: 10}).fill(0); // 創建 [0, 0, ..., 0] 的數組,長度爲10
list.forEach(el => newList[el] += 1); // 把數組元素記錄在 newList 上
return newList.reduce((pre, el, index) => { // 展開數組
for(let i = el; i; i--) {
pre.push(index)
}
return pre;
}, [])
}
6、基數排序和桶排序可以參考這篇文章
(https://juejin.im/post/5c69fa6cf265da2dc006475c)
二、遞歸
1、爬樓梯
設S(n)表示走n級臺階的走法數量,如果第一步走1級臺階,剩下的臺階數爲n-1,也就是說這種情況下的走法是相當於S(n-1);同理,如果第一步走2級臺階,剩下的臺階數爲n-2,這樣的走法相當於S(n-2);於是,得出遞推公式:S(n) = S(n-1) + S(n-2);
//遞歸實現
function climbstair(n){
if(n=== 1){
return 1
}else if(n====2){
return 2
}else{
climbstair(n) = climbstair(n-1) + climbstair(n-2)
}
}
//動態規劃實現 思想一致 ,方法不同,複雜度不同而已
var climbStairs = function(n) {
if(n== 1) return 1
let arr = new Array(n+1)
arr[1] = 1
arr[2] = 2
for(let i = 3 ; i <= n ; i++){
arr[i] = arr[i-1]+arr[i-2]
}
return arr[arr.length-1]
};
2、Array數組的flat方法實現
Array
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
Array.prototype.flat = function(arr){
var arr = []
this.foreach((item,index)=>{
if(Array.isarray(item)){
arr.concat(item.flat())
}
else{
arr.push(item)
}
})
return arr
}
//toString方法,連接數組並返回一個字符串 '2,2,3,2,3,4'
//split方法分割字符串,變成數組['2','2','3','2','3','4']
//map方法,將string映射成爲number類型2,2,3,2,3,4
arr.prototype.flat = function() {
this.toString().split(',').map(item=> +item )
}
3、二分查找
設定區間,low和high 找出口: 找到target,返回target; 否則尋找,當前次序沒有找到,把區間縮小後遞歸
function binaryFind(arr,target,low = 0 , hight = arr.length -1){
//Mathh.floor() 向下取整
var middle = Math.floor((low+hight)/2)
var con = arr[middle]
if(con === target){
return middle
}
else if(con > target){
return binaryFind(arr,target,low,middle-1)
}
else if(con<target){
return binaryFind(arr,target,middle+1,hight)
}
return -1;
}
三、樹
1、二叉樹的遍歷
//後序遞歸遍歷
function postOrder(node) {
if(node !== null) {
//左右根
postOrder(node.left);
postOrder(node.right);
console.log(node.show())
}
}
//先序遍歷
function preOrder(node) {
if(node !== null) {
//根左右
console.log(node.show());
preOrder(node.left);
preOrder(node.right);
}
}
//中序遍歷
2、二叉樹的尋找
//尋找特定值
function find(target,bst) {
var current = bst.root;
while(current !== null) {
if(target === current.data) {
return true;
}
else if(target > current.data) {
current = current.right;
} else if(target < current.data) {
current = current.left;
}
}
return -1;
}
//尋找最小值
function min(bst){
var current = bst.root;
while(current.left !== null) {
current = current.left;
}
return current.data;
}
//尋找最大值
function findMax(bst){
var current = bst.root
while(current.right !== null){
current = current.right
}
return current.data
}
3、二叉樹的構建
function insert(data) {
var node = new Node(data,null,null);
if(this.root === null) {
this.root = node
} else {
var current = this.root;
var parent;
while(true) {
parent = current;
if(data < current.data) {
current = current.left; //到左子樹
if(current === null) { //如果左子樹爲空,說明可以將node插入在這裏
parent.left = node;
break; //跳出while循環
}
} else {
current = current.right;
if(current === null) {
parent.right = node;
break;
}
}
}
}
}
四、常見算法題
1、字符串轉換問題
【題目】請編寫一段js函數,該函數的參數是一個駱駝命名法命名的變量標識符,
函數最終返回該標識符的下劃線命名法,如,輸入:abcDefGhi,返回:abc_def_ghi
function fun(value) {
let reg = /[A-Z]+/g;
return value.replace(reg,function (char) {
return "_"+char.toLocaleLowerCase();
})
}
console.log(fun("asdaBasdZasdk"));//asda_basd_zasdk
2、在一段連續的數組裏找出最大的連續子序列的和
var find = function(arr){
var min = 0 ; var ans = 0 ;
var sum
for(let i = 0 ; i < arr.length ; ++i){
sum+ = arr[i];
min = Math.min(min,sum)
ans = Math.max(ans,sum-min)
}
return ans;
}