【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);
}