js - 用两个栈实现队列 && 二叉树的镜像 && 旋转数组的最小数字

这篇博客涵盖了JavaScript中的数据结构和算法问题,包括单链表的排序、旋转数组求最小值、二叉树的镜像操作,以及用两个栈实现队列等。通过具体的代码实现,详细讲解了这些算法的思路和步骤,旨在提升读者在JavaScript中的算法能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

01- 单链表的排序

描述
给定一个节点数为n的无序单链表,对其按升序排序。

示例1
输入:[1,3,2,4,5]
返回值:{1,2,3,4,5}
思路:辅助数组,将原链表中的数据取出来放在一个新数组中,然后对这个数组进行排序,排序之后再将数组中的有序数据按照顺序插入链表中。

代码实现:

function sortInList( head ) {
    // write code here
    if(head == null) return head
    let numArr = []
    let node = head
    while(node){
        numArr.push(node.val)
        node = node.next
    }
    if(numArr.length === 1) return head
    numArr.sort((a , b) => a - b)
    let newHead = {
        val : numArr[0],
        next : null
    }
    let node2 = newHead
    for(let i = 1 ; i < numArr.length; i ++){
        let newNode = {
            val : numArr[i],
            next : null
        }
        node2.next = newNode;
        node2 = node2.next
    }
    return newHead
}

02- 旋转数组的最小数字

有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

示例1
输入:[3,4,5,1,2]
返回值:1
思路:二分法 
1.一个mid =(left + right)/2变量取数组区间的中间位置(向下取整)
2.比较这个中间值和最右边值的大小arr[mid] > arr[right]则缩减为mid后半部分 left = mid + 1 如果arr[mid] < arr[right] right = mid
(这里为什么总是和右边的数据比较大小? 原因是在数组旋转之前是升序数组,将数组前面若干数据放到元素组尾部之后,最右边的值就相当于是一个基准值,它前面可能存在有连续比它小的数据,也有可能自己就是最小。相较于中间mid位置的值来说如果大于arr[right]就说明当前这个元素在原始数组中时在arr[right]后面的,所以这个时候可以确定最小值肯定在[mid + 1, right]这个区间内。如果arr[mid] < arr[right] 则说明数组旋转的程度很大,将一半以上长度的数据旋转到了尾部,那此时说明arr[mid]这个值本来就是arr[right]左边的数据,所以最小值有可能就是arr[mid]自己本身或者前面的某一个值。所以缩减区间为[left,mid]) right = mid。
3.如果arr[mid] == arr[right] right -- 就从右边开始缩减整个数组的范围然后重新计算mid的值,重复上述两步操作 
4. i === j 退出循环,返回arr[i]即可

代码实现:

function minNumberInRotateArray(rotateArray)
{
    // write code here
    if(rotateArray.length === 0) return 0
    let left = 0 , right = rotateArray.length - 1
    while(left < right){
        let mid = Math.floor((left + right) / 2)
        if(rotateArray[mid] > rotateArray[right]) left = mid + 1
        else if(rotateArray[mid] < rotateArray[right]) right = mid
        else right --
    }
    return rotateArray[left]
}

03 - 二叉树的镜像

描述
操作给定的二叉树,将其变换为源二叉树的镜像。
在这里插入图片描述

思路:自底向上(递归):将每一个节点的左右孩子进行一个交换,一直到将根节点的两颗左右子树的交换,就可以生成原树的镜像

代码实现:

function Mirror( pRoot ) {
    // write code here
    if(pRoot == null) return pRoot
    function recursive(node){
        if(node == null) return 
        recursive(node.left)
        recursive(node.right)
        let temp = node.left
        node.left = node.right
        node.right = temp
    }
    recursive(pRoot)
    return pRoot
}

04 - 数组中出现次数超过一半的数字

给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

示例1
输入:[1,2,3,2,2,2,5,4,2]
返回值:2

思路:
1.将原数组去重得到一个新数组newArr
2.根据新数组的长度,在常见出一个次数数组numCounts
3.循环新数组中的数据比较其在原数组出现的次数,将次数分别放在元素对应下标的数组中
4.找到次数数组numCounts中最大的值,获取它的下标,通过下标将新数组中对应的数字返回即可

代码实现:

function MoreThanHalfNum_Solution(numbers)
{
    // write code here
    let newArr = [...new Set(numbers)]
    let numCounts = new Array(newArr.length)
    for(let i = 0 ; i < newArr.length; i ++){
        numCounts[i] = 0
        for(let j = 0; j < numbers.length; j ++){
            if(newArr[i] === numbers[j]){
                numCounts[i] ++
            }
        }
    }
    let max = Math.max.apply(null,numCounts)
    let index = numCounts.indexOf(max)
    return newArr[index]
}

05 - 数字在升序数组中出现的次数

描述
给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数

示例1
输入:[1,2,3,3,3,3,4,5],3
返回值:4
思路:双指针夹逼,left指针向右边指,right指针向左边指,最终符合条件了,返回left + right + 1即可
function GetNumberOfK(data, k)
{
    // write code here
    if(data[data.length - 1] < k) return 0
    let left = 0
    let right = data.length - 1
    while(left < right){
    	// 这里要做限制,防止left指针一直++ 形成死循环
        while(data[left] != k && left <= right) left ++
        // 这里也是一样
        while(data[right] != k && right >= left) right --
        return right - left + 1
    }
    if(data[left] === k) return 1
    else return 0
}

06 -用两个栈实现队列

描述:
用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。

思路:
1.栈结构先进后出,队列先进先出,所以两个栈一个作为压入数据的栈stakc1,一个作为弹出数据的栈stack2。stack2中的数据必须是从stack1中弹栈又重新压入stack2中的。
2.弹栈操作时,必须将现有栈stack2中的的数据全部弹完再去stack1中重新去数据

代码实现:

let stack1 = [] // 押入栈
let stack2 = [] // 输出栈
function push(node)
{
    // write code here
    stack1.push(node)
}
function pop()
{
    // write code here
    // 栈中有数据就直接弹出
    if(stack2.length) return stack2.pop() 
    else {
//      如果输出栈stack2中没有数据的时候才去押入栈中去拿
        if(stack1.length){
            while(stack1.length != 0){
                stack2.push(stack1.pop())
            }
            return stack2.pop()
        }else{
//          如果压入栈也没有数据,就表示队列里面没有数据 直接返回null
            return null
        }
    }
}

07 - 调整数组顺序使奇数位于偶数前面

描述
输入一个长度为 n 整数数组,数组里面不含有相同的元素,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

示例1
输入:[1,2,3,4]
返回值:[1,3,2,4]
思路:
1.一个存储全部元素的新数组newArr,将偶数按照顺序push到数组里面
2.一个保存前面奇数的数组prevArr,按照奇数本身原有的次序push到prevArr中
3.将prevArr数据展开放到,newArr的头部

代码实现:

function reOrderArray( array ) {
    // write code here
    let newArr = []
    let prevArr = []
    for(let i = 0 ; i < array.length; i ++){
        if(array[i] % 2 === 0){
            newArr.push(array[i])
        }else{
            prevArr.push(array[i])
        }
    }
    newArr.unshift(...prevArr)
    return newArr
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值