数据结构分类
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 = null让2-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
方法1:function hello(){
for(var i =0;i<3;i++){
setTimeout((function(i){
return function(){
console.log(i)
}
}(i)),i*1000)
}
}
方法2:function 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,输出两个数的乘积最小的