前端复习3

417 阅读4分钟

数据结构分类

Map(),哈希表

数组元素标号

["abc","bbc",123,"abc",123,"123"]function["1abc","bbc",1123,"2abc",2123,"123"]
分析 :Map()
用Map()来的key存储给出的元素,value存储个数,将value和key进行拼接,每次重复后,value值加1,最后修改value为1的key

function chAnge(arr){
   var hash = new Map()
   var res = []
   var l =arr.length
   for(var i = 0;i<l;i++){
   var hashValue = hash.get(arr[i])
   if(typeof(arr[i]) == 'string'){
   	if(hashValue !== undefined){   	
   		hash.set(arr[i],hashValue+1)
   		res.push(hash.get(arr[i])+arr[i])//
   	}else{
        hash.set(arr[i],1) 
        res.push(hash.get(arr[i])+arr[i])//1+'abc'='1abc'数字加字符串结果为字符串拼接
   	}
   }
   if(typeof(arr[i]) == 'number'){ 	 
   	if(hashValue !==  undefined){
   		hash.set(arr[i],hashValue+1)
   		res.push(parseInt(hash.get(arr[i]).toString()+arr[i]))
   	}else{
       hash.set(arr[i],1)
      res.push(parseInt(hash.get(arr[i]).toString()+arr[i]))
   	}

   } 
}
for(var j = 0;j<l;j++){
   	if(hash.get(arr[j])==1){
   		res[j] = arr[j]
   	}
   	return res
   } 

两数之和

function targetSum(arr,target){
    var hash = []
    for(var i = 0;i<arr.length;i++){
        var j = target -arr[i]
        if(hash[j] != undefined){
            return[hash[j],i]
        }else{
            hash[arr[i]] = i
        }
    }
}

找出字符串中出现最多的字符和次数

function findMaxDuplication(string){
	if(string.length == 1){
		return string
	}
	var arr = string.split('')
	var obj = {}
	for(var value of arr){
		if(obj[value]){
			obj[value] = obj[value] ++
		}else{
			obj[value] = 1
		}
	}
	let maxStr = ''
	let max = 1
	for(let j in obj){
		if {obj[j] > max}{
			maxStr = j;
			max = obj[j]
		}
	}
	return [maxStr,max]

}

链表

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。---双指针

右指针先移动k下,右指针.next代表倒数第0个

var kthToLast = function(head, k) {
   let right = head,left = head;
   while(k>0){
       right = right.next
       k--;
   }
   while(right !== null){
       left = left.next;
       right = right.next;
   }
   return left.val
};

删除链表中的重复元素---双指针

var deleteDuplicates = function(head) {
  var node=new ListNode(-1)
  node.next=head
  var slow=node
  var fast=node.next
  while(fast){
    if(fast.next && fast.next.val == fast.val){
      tmp = fast.val
      while(fast && tmp==fast.val)
        fast=fast.next
    }else{
      slow.next=fast
      slow=fast
      fast=fast.next
    }
    slow.next = fast//这里只是暂时的slow指针的下一个是fast,要等确定当前fast后面节点的跟当前不一样,才确定
  }
  return node.next
};
slow只是node的一个引用,指向了node的内存地址

反转链表

迭代法:
function reverseLink(head){
    var pre = null,curre = head,temp;
    while(curre){
        var temp = curre.next;
        curre.next = pre;
        pre = curre;
        curre = temp
    }
    return pre
}
递归法,递归法首先要有个终止条件,这种叫做先递归,再处理
1-2-3
head =1, head.next.next=head得出2-1,然后1-null,此时cur,3-2-1-null
head=2 head.next.next=head得出3-2,head.next = null2-null(此时cur,3-2-null)
head=3  return 3


function reverseLink(head){
    if(!head || head.next == null){
        return head
    }
    var cur = reverseLink(head.next)
    head.next.next = head
    head.next = null
    return cur
}

复杂链表的复制(递归)

function Node(val,next,random){
    this.val = val
    this.next = next;
    this.random = random
}
function Clone(head){
if(!head){
    return null
}
    var node = new Node(head.val)
    node.random = head.random
    node.next = Clone(head.next)
    return node
}

合并两个有序链表----递归调用

function sortLinklist(headA,headB){
    if(!headA){
        return headB
    }
    if(!headB){
        return headA
    }
    var head
    if(headA.val>headB.val){
        head =headB
        head.next = sortLinklist(headA,headB.next)
    }else{
        head = headA
        head.next = sortLinklist(headA.next,headB)
    }
}

数组、字符串

转置矩阵

['abc','dfe','hij'] => ['adh','bfi','cej']
[[a,b,c],[d,f,e],[h,i,j]] 字符串居然可以用str[index]的方法找索引

function change(arr){
	var l = arr.length
	var res =[]
	var result = []

	for(var i =0;i<arr[0].length;i++){
		var row=[]
		for(var j =0;j<arr.length;j++){
			row.push(arr[j][i])
		}
		 res.push(row)
	}
	console.log(res)
	for(var i = 0;i<arr[0].length;i++){
		result[i] = res[i].join('')
	}
	console.log(result)
}
change(['123','123','123','123'])

分发饼干---贪心策略

[1,2,3]是每个人至少多少饼干 [1,2]是饼干数---result = 2 g是小朋友们需要的饼干数,s是饼干数组

function findCount(g,s){
    var sIndex = 0,gIndex = 0,res = 0;
    s.sort((a,b)=>a-b);
    g.sort((a,b)=>a-b);
    while(sIndex<s.length && gIndex<g.length){
        if(s[sIndex]>g[gIndex]){
            res++
            gIndex++
        }
        sIndex++
    }
}

千分符

function paddingNum(num){
	var arr= num.toString().split('.')
	var arr1 = arr[0].split('').reverse()//整数部分
	if(arr[1]==undefined){
		arr[1] = ''
	}else{
		arr[1]='.'+arr[1]
	}
	var count = 0
		var j = 1
		var i	
	while(true){		
		i = 3*j+count;		
		if(isNaN(arr1[i])){
			var integ = arr1.reverse().join('')
			return integ  + arr[1]
		}else{
			arr1.splice(i,0,',')
			count++
			j++
		}

	}
}

合并两个排序好的数组

function(num1,m,num2,n){
		var i = m-1;
		var j = n-1;
		while(i>=0 || j>=0){
			if(num1[i]>num2[j]){
				num1[i+j+1] = num1[i]
				i--;
			}else{
                num1[i+j+1] = num2[j]
				j--;
			}
		}
	}

动态规划

青蛙跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。答案需要取模1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 本题与斐波那契数列求第n项值的一个道理

function numWay(n){
    if(n<3){
        return n
    }
    let two = 1,one = 2,sum;
    for(var i= 2;i<n;i++){
        sum = (one+two)%1000000007;
        one = sum;
        two = one;
    }
}

剑指 Offer 42. 连续子数组的最大和(贪心,动态规划)

输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。 要求时间复杂度为O(n)。

贪心
function maxSubArray(arr){
    var maxSum = sum =arr[0];
    for(var i = 1;i<arr.length;i++){
        sum = Math.max(arr[i],sum+arr[i])
        maxSum = Math.max(maxSum,sum)
    }
    return maxSum
}
动态规划
function maxSubArray(arr){
    var maxSum = arr[0]
    for(var i= 1;i<arr.length;i++){
        if(arr[i-1]>0){
            arr[i]=arr[i-1]+arr[i]  //arr[i]是前面子数组相加的结果
        }
        maxSum = Math.max(maxSum,arr[i])
    }
}

javascript中算法

闭包实现柯里化

柯里化:是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

function curry(fn){
    var args = []
    return function _curry(..._args){
        args = args.concat(_args)
        if(args.length == fn.length){
            return fn.apply(null,args)
        }else{
        return _curry
        }
    }
}
function fn(a,b,c){
    return a+b+c
}
var sum = curry(fn)
sum(1,2)(3);
sum(1)(2,3)
function add () {
    var args = [].slice.call(arguments);

    var fn = function () {
        var arg_fn = [].slice.call(arguments);
        return add.apply(null, args.concat(arg_fn));
    }

    fn.valueOf = function() {
        return args.reduce((a, b) => a + b);
    }
    return fn;
}
add(1)(2,3).valueOf()

每秒输出hello world的函数,要求第三次输出后停止,用闭包实现

算是闭包的一种使用场景。

打印字符串的时候不需要闭包也能实现,用闭包的话也行,看下面
function hello(){
    for(var i =0;i<3;i++){
        setTimeout(function(){
              console.log("helo world")        
        },i*1000)
    }
}
每隔一秒输出一个i,使用闭包保存变量i
方法1function hello(){
    for(var i =0;i<3;i++){
        setTimeout((function(i){
            return function(){
                console.log(i)
            }
        }(i)),i*1000)
    }
}

方法2function hello(){
   for(let i=1;i<=10;i++){
    setTimeout(function(){
        console.log(i);
    },1000*i);
}
}

手写原生promise.all

function promiseAll(promises){
 return new Promise(){
    if(isArray(promises){
        return reject(new Error('promises in not an array')
    }
    var resolveValue = []
    var resolveCount = 0
    var promiseNumber = promises.length
    for(var i = 0;i<promiseNumber;i++){
      Promise.resolve(promises[i]).then((value)=>{
          resolveValue[i] = value
          resolveCount++
          if(resolveCount === promiseNumber){
              return resolveValue
          }
      },(reason)=>{
          return reject(reason)
      }
      )
    }
   } 
}

算法分类

回溯算法

leetcode784.字母大小写全排列

var letterCasePermutation = function(S) {
  S = S.toLowerCase()
  let list = []
  function fn(num, s){
    list.push(s)
    for(let i = num; i < s.length; i++){
      let str = s.slice(0,i) + s[i].toUpperCase() + s.slice(i + 1)
      fn(i + 1, str)
    }
  }
  fn(0,S)
  return [...new Set(list)]
};

排序算法

冒泡排序

时间复杂度为n方、稳定排序

function bubbleSort(arr){
    var l = arr.length
    for (var i = 0;i < l-1;i++){
        for(var j = i+1;j<l;j++){
            if(arr[j] < arr[i]){
               let temp = arr[j]
               arr[j] = arr[i]
               arr[i] = temp
            }
        }
    }
}

快排

function quickSort(arr){
    if(arr.length == 1){
        return arr
    }
    let q = arr[0]
    let leftArr = []
    let rightArr = []
    for(let i = 0;i<arr.length;i++){
        if(arr[i]<=q){
            leftArr.push(arr[i])
        }else{
            rightArr.push(arr[i])
        }
    }
    return [].concat(quickSort(leftArr),[q],quickSort(rightArr));
    }
}

时间复杂度
当每次选择的数都为中间数的时候,才能达到快排最优解
T(n) = 2xT(n/2)+n
T(n) = 2x(2xT(n/4)+n/2)+n=4xT(n/4)+2n
T(n) = 4x(2x(T(n/8)+n/4)+2n = 8xT(n/8)+3n
这些1,2,3就是递归树的深度,T(1)=0,类似于二分法查找。所以T(n) = nT(1) + nlogn
快排不稳定快排不稳定意思是说对于数组中重复的数,第二个重复的可能会排列后到前面。

选择排序

时间复杂度n的平方,稳定排序

function selectSort(arr){
    var l =arr.length
    for(var i = 0;i<l-1;i++){
        var min =arr[0]
        var index =i
        for(var j = i+1;j++){
            if(arr[j]<min){
                min = arr[j]
                index = j
            }
        }
         if(index != i){
                var temp = arr[i]
                arr[i] = arr[index]
                arr[index] = temp
            }
    }
    return arr
}

插入排序

附一个插入排序的动画解释blog.csdn.net/weixin_4115…
时间复杂度n的平方,稳定排序

function insertSort(arr){
    var l = arr.length
    for(var i = 0;i<l-1;i++){
        var insert = arr[i+1]
        var index = i+1
        for(var j = i,j>=0;j--){
            if(insert<arr[j]){
                arr[j+1] = arr[j]
                index = j
            }
        }
        arr[index] = insert
    }
    return arr
}

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的