剑指offer刷起来

1.二维数组的查找

function FindArray(arr){
    return arr.some(arr=>arr.some(e=>e===target))
}
  • 数组排序
function SortArray(arr){
  return  array=arr.sort((a,b)=>a-b)
}//升序

2.替换空格

function replaceSpace(str){
  return  arr.replace('/\s/g','%20')
}

3.从尾到头打印链表

​ 链表:数组之间加指针 p.head p.next

function printListFromTailToHead(head){
    var p=head
    var result=[]
    while(p){
        result.unshift(p.val)//从尾到头
        //result.shift(p.val)//从头到尾
        p=p.next
    }
    return result
}

4.重建二叉树

  • 二叉树遍历:
    • 前序遍历(先序):根|左|右(下面的也是先根再左后有)
    • 中序遍历:左下开始,左|根|右(都是左下开始)
    • 后序遍历:左下开始,左|右|根
function TreeNode(x){
    this.val=val
    this.left=null
    this.right=null
}
//pre前序;Vin中序
function TreeReBulit(pre,vin){
    if(pre.length===0||vin.length===0){
        return null
    }
    var index=vin.indexOf(pre[0])//找根
    var left=vin.slice(0,index)
    var right=vin.slice(index+1)
    
    var node=new TreeNode[pre[0]]
    node.left=TreeReBulit(pre.slice(1,index+1),left)//前序,后序,递归
    node.right=TreeReBulit(pre.slice(index+1),right)
    return node
}

5.两个栈实现队列

  • js一个栈就可以
var stack1=[]

function push(node)
{
    stack1.push(node)//队列中enqueue直接push即可(clear也不需要)
}
function pop()
{
    // write code here
    return stack1.shift()//其他均需要return
}

知识点:完整的队列类的实现

function Queue(){
    var items=[]
    this.enqueue=function(element){
        items.push(element)
    }//添屁股--添后
    this.dequeue=function(){
        return items.shift()
    }//删头头--与栈不同,先入先出,删头
}

6.旋转数组的最小数字

function minNumberInRotateArray(rotateArray)
{
    // write code here
    if(rotateArray.length===0){
        return 0
    }
    var array=[]
    array=rotateArray.sort((a,b)=>a-b)
    return array[0]
}
//终于上道了,自己第一个完全通过的js代码哈哈哈哈哈哈

7.斐波那契数列

function Fibonacci(n)
{
    // write code here
    if(n===0)
        return 0
    if(n===1||n===2){
        return 1
    }
    return Fibonacci(n-1)+Fiboacci(n-2)
}//递归会产生栈的溢出

//普通方法
function Fibonacci(n)
{
    // write code here
    var f0=0,
        f1=1,
        fn=1    
    for(let i=2;i<=n;i++){
       fn=f0+f1
       f0=f1
       f1=fn       
    }
    if(n===0){
        return 0
    }else{
        return fn
    }
    
}

8.跳台阶(一次只跳一阶或二阶)

//通过带入数值发现规律--本质为斐波那切数列
function jumpFloor(number)
{
    // write code here
    if(number===0||number==1){
        return 1
    }
    return jumpFloor(number-1)+jumpFloor(number-2)
}

9.跳台阶(一次可跳到n阶)

//通过带入数值发现规律--本质为2*f(n-1)
function jumpFloorII(number)
{
    // write code here
    if(number===0||number===1){
        return 1
    }   
    return jumpFloorII(number-1)*2
}

10.矩形覆盖

//通过带入数值发现规律--本质为f(n-1)+f(n-2)
//注意边界问题
function rectCover(number)
{
    // write code here
    if(number<=2){
        return number
    }
    return rectCover(number-1)+rectCover(number-2)
}

11.二进制中1的个数

  • 二进制码相关知识
    • 原码:符号位加上真值的绝对值,第一位表示符号(0正;1负)
    • 反码: 正数是本身;负数符号位不变,其余各个位取反.
    • 补码:正数是本身;负数 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
  • js中的整数的表示范围是[-2^31, +2^31-1],即[-2147483648, +2147483647],
  • 需要注意的API
    • number.toString(),不传参转为字符串 ;传参转为进制数字符串
    • Array.from();将伪数组转化为真正的数组
    • array.filter();过滤,符合条件的返回一个新数组
    • array.some();遍历,有一个符合条件返回true
    • array.every();遍历,全符合条件返回true
//第一次写的;走了弯路,只能完成大于0的数字,对负数没办法判断
function NumberOf1(n)
{
    // write code here
    arr=Array.from(n.toString(2))
    return (arr.filter(e=>e==1)).length
    
}
//正确方法,注意最底层的思路,对位操作符号应该熟悉
function NumberOf1(n)
{
    // write code here
    var count = 0,flag=1;
    while(flag){
        if(n&flag)count++;
        flag=flag<<1;
    }
    return count;
}

12.数值的整次方

  • a**b
  • Math.pow(a,b)
function Power(base, exponent)
{
    // write code here
    if(base===0&&exponent===0){
        return null
    }
    return base**exponent
}
//或 Math.pow(base,exponent)

13.调整数组顺序使奇数位于偶数前面

  • array.filter()
  • array.concat();参数为字符串;参数为数组前后拼接
function reOrderArray(array)
{
    // write code here
     arr1=array.filter(e=>e%2===1)
     arr2=array.filter(e=>e%2===0)
     return arr1.concat(arr2)
}

14.链表中倒数第k个结点

//这个方法真的妙,将链表转化成数组,直接根据位置打印出数据即可,太妙了
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function FindKthToTail(head, k)
{
    var arr = [];
    while(head!=null){
        arr.push(head);
        head = head.next;
    }
    return arr[arr.length-k];
}

//这种方法还不太理解
 
function FindKthToTail(head, k)
{ 
    var p = head
    var q = head
    for(var i = 0; p && i< k; i++){
         p= p.next
    }
    if( i < k ){
       return null
    }
    while(p != null ){
         p = p.next
         q = q.next
    }
    return q
}

15.反转链表

  • 利用数组push pop与链表转换,注意返回值根据题目要求
  • 链表的本质就是数组元素前后加指针
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function ReverseList(pHead)
{
    // write code here
    var arr=[]
    var node=pHead
    while(node!=null){
        arr.push(node.val)
        node=node.next
    }
    //执行到这里node为null
    node=pHead
    while(node!=null){
       node.val=arr.pop()
        node=node.next
    }
    return pHead
    
}

16.合并两个排序的链表

  • 注意链表是对象,要用list={},不是数组,是每个元素带有指向的数组
  • 自己代码的问题需要再研究一下(自己看了好久没看出来)
//自己写的代码,有问题
/*function ListNode(x){
    this.val = x;
    this.next = null;
}*/
function Merge(pHead1, pHead2)
{
    // write code here
    var node1=pHead1
    var node2=pHead2
    var node3
    var arr=[]
    var array=[]
    while(node1.next!=null){
        node1=node1.next
    }
    node1.next=node2
   
    while(node1.next!=null){
        arr.push(node1.val)
        node1=node1.next
    }
    array=arr.sort((a,b)=>a-b)
    node1=pHead1
    while(node1.next!=null){
        node1.val=arr.shift()
        node1=node1.next
    }
    return pHead1
    
}

//正确的代码
function Merge(pHead1, pHead2) {
    // write code here
    if (pHead1 == null) {
        return pHead2;
    } else if (pHead2 == null) {
        return pHead1;
    }
    var result = {};
    //哪个小先把哪个放在新的链表里面
    if (pHead1.val < pHead2.val) {
        result = pHead1;
        result.next = Merge(pHead1.next, pHead2);
        //小的在前面,然后把剩下的再比较
    } else {
        result = pHead2;
        result.next = Merge(pHead1, pHead2.next);
    }
    return result;
}

17.树的子结构

//有点抽象,我的思路,首先A||B无论谁为空都返回null
//找,找A中有无,有的话从B的根节点
//找到的话找B的左子树在 找到的 A中的左子树中找根 然后 找B的右子树
//当B全部遍历完之后,如果有一个错误,则返回false
//其余的均返回true

//正确答案
/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function HasSubtree(pRoot1, pRoot2)
{
    if(pRoot2==null || pRoot1==null)
        return false;
    return isSubtree(pRoot1,pRoot2)||
            HasSubtree(pRoot1.right,pRoot2) ||
            HasSubtree(pRoot1.left,pRoot2);
}
function isSubtree(pRoot1,pRoot2){
    if(pRoot2 == null) return true;
    if(pRoot1 ==null) return false;
     if(pRoot1.val == pRoot2.val){
         return isSubtree(pRoot1.left,pRoot2.left) &&
                isSubtree(pRoot1.right,pRoot2.right);
     }else{
         return false;
     }
}

//另一种正确的解法
function HasSubtree(p1, p2, flag) {
    var f = HasSubtree;
    if(flag && !p2) return true;
    if(!p1 || !p2) return false;
    if(p1 && p2 && p1.val == p2.val)
        return f(p1.left,p2.left,true) && f(p1.right,p2.right,true) || f(p1.left,p2)||f(p1.right,p2);
    return  f(p1.left,p2) || f(p1.right,p2);
}

18.二叉树的镜像

  • 左右互换,递归下去
/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function Mirror(root)
{
    // write code here
    
    if(root==null){
        return null
    }else if(!root.left&&!root.right){
        return null
    }
    var t={}
    t=root.left
    root.left=root.right
    root.right=t
    
    if(root.left){
        Mirror(root.left)
    }
    if(root.right){
        Mirror(root.right)
    }
    return root
    
}

19.顺时针打印矩阵

function printMatrix(matrix)
{
    //为空返回null
    if(matrix==''||matrix.length==0){
        return null;
    }
    
    var a=matrix.length;
    var b=matrix[0].length;
    var r=matrix.length,
        c=matrix[0].length;
    var result=[],
        start=0;
    //当
        while(r>2*start&&c>2*start){
            var endx=c-start;
            var endy=r-start;
            for (var i = start; i < endx; i++) {
                result.push(matrix[start][i])
            }
            if(start<endy-1){
                for (var j= (start + 1); j < endy; j++) {
                result.push(matrix[j][endx-1]);
                }
            }
            if(start<(endx-1)&&start<(endy-1)){
                for (var  m = endx-2; m >= start; m--) {
                    result.push(matrix[endy-1][m])
                }
            }
            if(start<(endx-1)&&start<endy){
                for (var n = endy - 2; n >= start+1; n--) {
                    result.push(matrix[n][start])
                }
            }
            start++
        }
        return result;
}

20.包含min函数的栈

  • 栈的实现:push返回的是新的长度,但stack此时为改变的数组(unshift也一样)
  • pop与shift均返回的是删除的元素,stack为执行之后的数组
var stack = [];
var minStack = [];
 
function push(node)
{
    stack.push(node);
    //若最小栈里面数值大于新插入的node,则将这个node也push到min栈里面
    if( minStack.length === 0 || minStack[minStack.length - 1] > node){
        minStack.push(node);
    }
}


function pop()
{
    // 为空返回null
    if( stack.length === 0 ){
        return null;
    }
    //不为空则删除,
    var node = stack.pop();
    if( minStack[minStack.length - 1] === node){
       minStack.pop();
    }         
    return node;
}


function top()
{
    if(stack.length === 0){
        return null;
    }else{
        return stack[stack.length - 1];
    }
}
function min()
{

    if(minStack.length === 0){
        return null;
    }else{
        return minStack[minStack.length - 1];
    }
}

21.栈的压入、弹出序列

function IsPopOrder(pushV, popV) {
  var stack = [];
  var idx = 0;
  for (var i = 0; i < pushV.length; i++) {
    stack.push(pushV[i]);
      //遍历,入栈
      //当栈有序列并且栈顶为出栈的序列时候,出栈
    while (stack.length && stack[stack.length - 1] == popV[idx]) {
      stack.pop();
      idx++;
    }
  }
    //完全出栈后如果stack长度为0,则说明该pop序列是该pushV序列的弹出
  return stack.length == 0;
}

22.从上往下打印二叉树

  • 看成一个队列,先根|再左|后右;每次打印根的时候,将左右子树全部放到队列里面,然后根据顺序再往下打印;看成队列看成队列看成队列(自己就是这里没想明白,用队列一下就解决了)
  • 善用中间数组,数组的四个基本属性有大用处
function PrintFromTopToBottom(root)
{
    // write code here
    var arr=[];
    var data=[];
    if(root!=null){
        arr.push(root);
    }
    while(arr.length!=0){
        var node=arr.shift();
        if(node.left!=null){
            arr.push(node.left);
        }
        if(node.right!=null){
            arr.push(node.right);
        }
        data.push(node.val);
    }
    return data;
}

23.二叉搜索树的后序遍历序列

  • splice从数组中删除指定的一个或多个元素,返回结果为新的数组,会改变原数组
//我写的代码的问题:只判断了去掉根节点数组为递增序列
function VerifySquenceOfBST(sequence)
{
    // write code here
    var arr=[]
    var t='Yes'
    if(sequence.length==0){
        return false
    }
    sequence.pop()
    for(let i=0;i<sequence.length;i++){
        if(sequence[i]<sequence[i-1]){
             return t='No'
        }
    }
    return t
    
}

//正确的代码1,循环跑的比较多,比较费内存
思路为所有大于根节点和小于根节点的长度下来等于总长则正确,如果
function VerifySquenceOfBST(sequence) {
    if (!sequence.length) return false;
    var count = 0;
    var len = sequence.length;
    while (len) {
        len--
        var root = sequence[len]                //后序遍历的最后一个是根节点,然后根节点随len变化
        while (sequence[count] < root) count++; //左子树上所有结点的值均小于它的根结点的值
        while (sequence[count] > root) count++;//右子树上所有结点的值均大于它的根结点的值;
        if (count < len){
            return false;   //左右子树所有大于或小于根节点的值和count===0才能代表是二叉搜索树
            count = 0;                      //进入下一根节点
        }
    }
    return true;
}

//正确思路代码
function VerifySquenceOfBST(sequence) {
      if(sequence.length==0){
          return false;
      }
      var root = sequence.pop();
    
      if(sequence.length==0){
        return true;
      }//只有一个root的1长度也满足条件,返回true
    
   	 //找出根节点的左节点,将位置记录为idx
      var idx = -1;
      for (var i = 0; i < sequence.length - 1; i++) {
        if (sequence[i] > root) {
          idx = i;
          break;
        }
      }
     //找右子树,用splice已经将数组右子树切割,sequence为左子树
      var righttree = idx == -1 ? [] : sequence.splice(idx);
 
      var lefttree = sequence;
   
      var right = righttree.every(e=>e>root)
     //一直执行下去,保证每个左右子树都符合后序遍历 ,返回true
      if (right) {
        if (lefttree.length == 0) {
          return VerifySquenceOfBST(righttree);
        } else if (righttree.length == 0) {
          return VerifySquenceOfBST(lefttree);
        } else {
          return VerifySquenceOfBST(lefttree) && VerifySquenceOfBST(righttree);
        }
      } else {
        return false;
      }
    }

24.二叉树中和为某一值的路径

  • slice从数组中提取指定的一个或多个元素,返回结果为新的数组

function FindPath(root, expectNumber) {
    var result = [];
    if (root === null) {
        return result;
    }
    dfsFind(root, expectNumber, [], 0, result);
    return result;
 
}
function dfsFind(root, expectNumber, path, currentSum, result) {
    currentSum += root.val;
 
    path.push(root.val);
 
    if (currentSum == expectNumber && root.left == null && root.right == null) {
        result.push(path.slice(0));
        //这一步将找出来的直接到叶节点的路径先打印出来
    }
    if (root.left != null) {
        dfsFind(root.left, expectNumber, path, currentSum, result);
    }
 
    if (root.right != null) {
        dfsFind(root.right, expectNumber, path, currentSum, result);
    }
 	//都不满足则删除这个node.val,往上后退一步 ,再找右子树
    path.pop();
}

25.复杂链表的复制


26.二叉搜索树与双向链表


27.字符串的排列

//正确的思路,方式1
var result = [];
function Permutation(str){
    result = []
    if(str.length<=0) return result;
    var sortTmp = "";
    var arr = str.split("");
    result = sortString(arr,sortTmp)
    return result;
}

function sortString(arr,sortTmp){
    if(arr.length ==0 ){
        result.push(sortTmp);
    }else{
        var isRepeated = {}
        for(var i = 0; i<arr.length; i++){
            if(!isRepeated[arr[i]]){
                var p = arr.splice(i,1)[0];
                sortTmp += p;
                sortString(arr,sortTmp);
                arr.splice(i,0,p); //恢复字符串
                sortTmp = sortTmp.slice(0,sortTmp.length-1);
                isRepeated[p] = true;
            }
        }
    }
    return result;
}
//第二种,递归的方式
function Permutation(str)
{
    // write code here
    if(str.length == 0)return '';
    let str_arr = str.split('');
    str_arr.sort();
    let res = [];
    for(let i = 0; i < str_arr.length; i++){
        if(i > 0 && str_arr[i] === str_arr[i-1])continue;
        let front = str_arr.slice(0,i);
        let end = str_arr.slice(i+1);
        PermutationHelp(res,str_arr[i],front.concat(end));
    }
    return res;
     
}
function PermutationHelp(res,temp, arr){
    if (arr.length === 0) {
        res.push(temp);
    } else {
        for(let i = 0; i < arr.length; i++){
            if(i > 0 && arr[i] === arr[i-1])continue;
            let front = arr.slice(0,i);
            let end = arr.slice(i+1);
            PermutationHelp(res,temp+arr[i],front.concat(end));
        }
    }
}



//我的代码,有问题
function Permutation(str)
{
    // write code here
    var arr=[]
    arr=str.split('')
    if(arr.length<=0){
        return []
    }

    for(let i=0;i<arr.length;i++){
        
        for(let j=i+1;j<arr.length;j++){
            var t=arr[i]
            arr[i]=arr[j]
            arr[j]=t
        }
        return arr.join('')
    }
}

28.数组中出现次数超过一半的数字

//正确方式
function MoreThanHalfNum_Solution(numbers)
{
    // write code here
    var len=numbers.length;
    if(len==0)return 0;
    var num=numbers[0];
        count=1;
    for(var i=0;i<len;i++){
        if(num==numbers[i]){
            count++;
        }else{
            count--;
        }
        if(count==0){
            num=numbers[i];
            count=1;
        }
    }
    count=0;
    for(var i=0;i<len;i++){
        if(numbers[i]==num)count++;
    }
    if(count*2>len)return num;
    return 0;
}









//我的代码
function MoreThanHalfNum_Solution(numbers)
{
    // write code here
   var t=0
   if(numbers.length==0){
       return t
   }
    var arr=numbers.sort((a,b)=>a-b)
    var index=0
    for(let i=0;i<arr.length-1;i++){
        if(arr[i]==arr[i+1]){
              t=arr[i]
             index++
        }else{
            index=0
        }
        
        if(index>(arr.length/2)){
             return t
        }
    }
}

29.二维数组的查找


30.二维数组的查找


1.二维数组的查找


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值