JavaScript 算法题

此算法基础必须掌握,以下是个人JavaScript算法题积累,持久更新ing...
建议:新手入门可以配合看书籍:《算法图解》

1、如下题:

在这里插入图片描述

三个for循环

indexOf() 内部也是一个循环,所以是三个for循环。
时间复杂度为 :T(n) =  O(n^3)
let nums = [2, 7, 8, 6, 5, 3, 1, 11, 15]
let target = 9

function sum(arry, target) {
    // 双重for循环遍历数组,进行判断后将符合的去和数组作indexOf() 找到对应的索引值
    let arr = arry
    for (let i = 0; i < arr.length; i++) {
        let ele = arr[i]
        for (let j = 1; j < arr.length; j++) {
            let nele = arr[j]
            if (ele + nele == target) {
                console.log([arr.indexOf(ele), arr.indexOf(nele)])
                arr[i], arr[j] = null
            }
        }
    }
}

sum(nums, target)

俩个for循环

此时的时间复杂度为:T(n) =  O(n^2)
let nums = [2, 7, 8, 6, 5, 3, 1, 11, 15]
let target = 9

// 通过temp中间变量来接受,目标值-当前循环的值(差值)
// 在通过temp的值去和原数组判断是否相等
function funny(arry, target) {
    let arr = arry
    for (let i = 0; i < arr.length; i++) {
        let temp = target - arr[i]
        for (let j = 1; j < arr.length; j++) {
            if (arr[j] === temp) {
                arr[i], arr[j] = null
                console.log([i, j])
            }
        }
    }
}

funny(nums, target)

一个for循环

此时的性能最佳,时间复杂度为:T(n) =  O(n)
/**
 * 
 * @param {*传入的数组} arry 
 * @param {*目标值} target
 * 
 * 此方法用的是哈希算法。
 * 将arr数组变为了一个伪数组对象。键是元素,对应的值是索引 
 * 
 */
function fun(arry, target) {
    let arr = []
    for (let i = 0; i < arry.length; i++) {
        let temp = target - arry[i]
        if (arr[temp] !== undefined) {
            console.log([arr[temp], i])
        } else {
            arr[arry[i]] = i
        }
    }
}
// arry = [2, 7, 8, 6, 5, 3, 1, 11, 15]
// temp=7, 2=>0,
// temp=2, 7=>1
// temp=1, 8=>2
// temp=3, 6=>3
// temp=4, 5=>4 
// ............

fun(nums, target)

2、旋转链表

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

思路

主要的思路就是找到旋转后的第一个结点,我们可以在遍历的过程中添加反向指针prev形成双向指针来方便我们获取结点,注意当k等于或超过列表长度时,我们要进行取余操作

链表中的点已经相连,一次旋转操作意味着:

  • 先将链表闭合成环
  • 找到相应的位置断开这个环,确定新的链表头和链表尾

)

新的链表头:在位置 n-k 处,其中 n 是链表中点的个数。

新的链表尾:新的链表尾就在头的前面,位于位置 n-k-1。

我们这里假设 k < n

如果 k >= n 怎么处理?

k 可以被写成 k = (k // n) * n + k % n 两者加和的形式,其中前面的部分不影响最终的结果,因此只需要考虑 k%n 的部分,这个值一定比 n 小。

算法

找到旧的尾部并将其与链表头相连 old_tail.next = head,整个链表闭合成环,同时计算出链表的长度 n。
找到新的尾部,第 (n - k % n - 1) 个节点 ,新的链表头是第 (n - k % n) 个节点。
断开环 new_tail.next = None,并返回新的链表头 new_head。

代码

var rotateRight = function(head, k) {
  	// 如果是 空链表或者只有一个元素的链表,则返回该链表
	if(!head || !head.next) return head
	var cur = head
	// 从头部开始循环,获取链表长度。由于头部也是一个节点,所以 length 初始值为1
	var length = 1;
	while(cur.next) {
	    cur = cur.next
	    length++
	}
	// 获取实际要重复的次数
	var num = k % length
	// 链表闭环
	cur.next = head
    
	var new_list = head
	// 找到新的尾部 new_tail : 走length -  k % length - 1 步
	// 找到新的头部 new_head : 走length -  k % length 步
	for(var i = 0;i < length - num - 1 ; i++){
		new_tail = new_tail.next
	}
	var new_head = new_tail.next
	new_tail.next = null
	return new_head
};

var rotateRight = function(head, k) {
    
    let len = 0;
    let linkHead = head;
    
    if (!head || k === 0) return head;
    if (head.next == null) return head;
    

    let prev = null;
    
    while(head) {
        len++;
        head.prev = prev;
        prev = head;
        head = head.next;
    }
    let linkLast = prev;

    k = k % len;

    if (k === 0) return linkHead;

    while(k > 1) {
        prev = prev.prev;
        k--;
    }

    linkLast.next = linkHead;
    prev.prev.next = null;
    return prev;

};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值