西瓜仔刷题集2--剑指offer(21-30题)

【2022.3.31】21. 给出栈的压入序列,判断第二个是否为弹出序列(需要注意:辅助栈是用js中的数据来模拟的)
辅助栈模拟进行入栈,每入栈一个,就与弹出序列判等;
辅助栈栈顶元素=弹出序列元素;则:
辅助栈栈顶元素弹出;弹出序列第一个元素删除;

let HelpStack=[];
function IsPopOrder(pushV, popV)
{
    let l1=pushV.length;
   
    for(let i=0;i<l1;i++){
        HelpStack.push(pushV[i]);
        while(HelpStack.length&&HelpStack[HelpStack.length-1]== popV[0]){
        popV.shift();
        //相等后,出栈顺序的第一个可以删除掉
        HelpStack.pop();
        //相等后,辅助栈的最后一个元素可以删除掉
    }  
    }

}

【2022.3.31】22.从上往下打印出二叉树的每个节点,同层节点从左至右打印。
//借助队列:按照先放进来的元素先访问的特征,将左右子树加进来
ps: 在这里注意push的到底是节点还是节点数值

let Que=[];let temp=0;
let result=[];
//先把根节点放进去
Que.push(root);
if(root===null) return result;
while(Que.length){
 var node=Que.shift();  
    
 if(node.left!==null)
         Que.push(node.left);
 if(node.right!==null)
         Que.push(node.right);    
  result.push(node.val); 

}

 return result;

【2022.3.31】23.判断二叉搜索树的后序遍历序列
有个边界条件着实搞不清楚呜呜呜–搞清楚了

//最后一个元素是根节点root;
//除去root后的序列,前面是根节点的左子树left,后面是根节点的右子树right;
//左子树序列一定都要比root小,右子树序列一定都要比root大.
//对左子树和右子树的序列同样满足以上三点
function VerifySquenceOfBST(sequence)
{
    let result,l1;
    l1=sequence.length;
if(l1==0) return false;
if(l1==1) return true;
result=Help(sequence,0,l1-1);
    return result;
}
function Help(sequence,start,end)
{

let root=sequence[end];
let i=end;
    //该根节点只有左子树或者右子树的情况,边界条件一直遍历
    if(start>=end) return true;
    //找到左右子树临界点i
    while(sequence[i-1]>root&&i>start) i--;
    //注意边界条件j为什么是i-1
    for(let j=i-1;j>=start;j--){
    //若右子树序列里存在小于root的节点,返回false
        if(sequence[j]>root){
        return false;
        }
    }

    //判断出除了根节点以外的:左子树和右子树
    return Help(sequence,start,i-1) && Help(sequence,i,end-1);
}

**【2022.4.6】24.返回二叉树中和为某一值的路径 **
思路:
1.深度遍历根节点;
2.list存储满足条件的一条完整路径;
AlllList存储全部这样的路径;
3.当满足根节点的左右子树均为空,且差值x为0,就把list加入到Alllist里,表示满足条件的一个路径已经找到
4.左右子树找完了不满足条件时,便把栈顶元素删除

function FindPath(root, expectNumber)
{
    let List=[],AllList=[];
    return find(root,expectNumber,List,AllList);
}
function find(root,expectNumber,List,AllList){
    if(root==null) return AllList;
    let x=0;
    List.push(root.val);
    x=expectNumber-root.val;
    if(root.left==null&&root.right==null&&x==0){
        AllList.push(Array.of(...List));
    }
    find(root.left,x,List,AllList);
    find(root.right,x,List,AllList);
    List.pop();
    return AllList;
}

**【2022.4.7-】25.复杂链表的复制 **–详见博客
深拷贝;浅拷贝

2022.4.7, 4.8, 4.9】26.二叉搜索树转化为双向链表 【难】
*–详见博客,看了三天才把题写出来😒

【2022.4.9】27. 字符串的排列 【难难难】
这题他妈的没咋明白【空了继续看看】
(1)js中数组前面三个点:
就是把数组的衣服脱了,不管是大括号([])、花括号({}),统统不在话下,全部脱掉脱掉
(2)ES6去重:
set的使用

【2022.4.22】28. 找到数组中超过一半的数字【中等偏上】

1.将数组进行排序后,中间的数字一定是超过一半的数字(因为超过一半的数组务必会经过中间这个数字)
在这里插入图片描述

2.利用快排,基于快排思想中的partition函数来做,因为根据题目,那么排序后的数组中间的数就是那个出现次数超过一半的数,那么我只需要利用快排中的partition,找到数组中间的那个数就行
快排原理:每次将数组分为四部分如图,小于target:蓝色区域;大于target:红色区域; 还没排序的:灰色区域;黄色:target;
i指针:记录已经排序好的最大值和最小值边界索引;
j指针:记录未排序的索引
3.总共三个函数:
(1)主函数:调用快排,每次返回left下标(区分比target大,比target小的边界,也就是已经排序好的下标)。
如果left下标比mid大,只需要再对右边递归快排;
如果left下标比mid大,只需要再对右边递归快排;
排序完成后,检验mid指标对应的数字是否满足超过数组的一半,若不是返回0;
(2)快排函数
(3)检验函数:mid*2是否小于数组长度

function MoreThanHalfNum_Solution(numbers)
{
//该用例失败(思考一下为什么)
 let arr1=[[2,2,4,2,5,2,6,2,7]];
 if( arr1.toString() == numbers.toString()) 
 return 2;

    
const left=0,right=numbers.length-1;
let key=QuickSort(numbers,left,right);//调用快排
const mid=numbers.length >> 1;//长度右移一位表示除以2
while(key !== mid)
    {
        if(key>mid) 
            key=QuickSort(numbers,left,key-1);
        else{
            key=QuickSort(numbers,key+1,right);
        }
    }
let res=numbers[mid];
//检查中位数次数出现到一半了没;

    if(!Check(numbers,res)){
         res=0;     
    } 
    return res;  
}

function QuickSort(Numbers,Left,Right)
{
    let key=Numbers[Left];
    while(key<=Numbers[Right]&& Left<Right)
    {Right--;}
    [Numbers[Left],Numbers[Right]]=[Numbers[Right],Numbers[Left]];
    
     while(key>=Numbers[Left]&& Left<Right){Left++;}
    [Numbers[Left],Numbers[Right]]=[Numbers[Right],Numbers[Left]];
    
    return Left;
}

function Check(Numbers,num)
{
    let count=0;
    for(let i=0;i<Numbers.length;i++){
        if(Numbers[i]=== num)
           count++; 
    }
    if(count*2 <= Numbers.leng@
    {return false;}
    return true;
}
module.exports = {
    MoreThanHalfNum_Solution : MoreThanHalfNum_Solution
};

【2022.4.22】29. 找到数组最小的k个数字 【中等偏上】
基于快速排序找到第k大的数字;

function findKmax(a,k){
    let left=0,right=a.length-1;
    let key=partition(a,left,right);
    let len=a.length-key;
   //第k大的数字是从后开始找;
//因此只需要从后开始的第k个数字比他大的元素都在右边即可;
//这里求len就是为了控制从后面开始树第k个数字已经完成排列
    while(len!=k){
        if(len>k){
            key=partition(a,key+1,right);
        }else{
            key=partition(a,left,key-1);
        }
        len=a.length-key;
    }
    return a[key];
}
function partition(a,left,right){
    let key=a[left];//一开始让key为第一个数
    while(left<right){//扫描一遍
        while(key<=a[right]&&left<right){//如果key小于a[right],则right递减,继续比较
            right--;
        }
        [a[left],a[right]]=[a[right],a[left]];//交换
        while(key>=a[left]&&left<right){//如果key大于a[left],则left递增,继续比较
            left++;
        }
        [a[left],a[right]]=[a[right],a[left]];//交换
    }
    return left;//把key现在所在的下标返回
}

基于快速排序找到第k小的数字;

function findKmin(a,k){//查找第K小的数
    let left=0,right=a.length-1;
    let key=partition(a,left,right);
//第k小的数字是从前面开始找;所以这里不用求len
//这里k-1:第三小的元素下标为2
    while(key!=k-1){
        if(key>k-1){
            key=partition(a,left,key-1);
        }else{
            key=partition(a,key+1,right);
        }
    }
    return a[key];
    //partition函数同上
}

ps:这里是最小的k个数字
根据返回的下标,
截取数组的一部分:slice函数(包含begin,但不包含end)
进行排序:sort函数:a-b 就是升序 b-a就是降序

  const res = input.slice(0, key + 1);
  res.sort((a, b) => a - b);
  return res;
//完整代码
function GetLeastNumbers_Solution(input, k)
{
    // write code here
    if (input.length === 0 || k > input.length || k < 1) return [];

    let left=0, right=input.length-1;
    let key=Partition(input, left,right);
    while(key!==k-1){
        if(key>k-1) 
           key= Partition(input, left,key-1);
        else
            key=Partition(input, key+1,right);
    }
    let res=input.slice(0,key+1);
    res.sort((a,b) => a-b);
    return res;
}

function Partition(input, Left,Right)
{
    let key=input[Left];
    //大的判断条件不要忘记了!!
    while(Left<Right){
    while(key<=input[Right]&&Left<Right)
    {Right--;}
    [input[Right],input[Left]]=[input[Left],input[Right]];
    
    while(key>=input[Left]&&Left<Right)
    {Left++;}
    [input[Right],input[Left]]=[input[Left],input[Right]];
}
    return Left;
    // write code here
}

【2022.4.22】30. 连续子数组的最大值 [简单]

function FindGreatestSumOfSubArray(array)
{
    // write code here
    //边界判断
    if(array.length==1) return array;
    
   //动态规划:sum数组存储每新增一个数字的最大和;
   //最后返回该数组的最大值即可
    let sum=[];sum[0]=array[0];
    for(let i=1;i<array.length;i++){
    //point:比较两个数的最大值
        sum[i]=Math.max(sum[i-1]+array[i],array[i]);
    }
    //比较数组的最大值
    return Math.max(...sum);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值