【JavaScript算法】-链表合辑02

一、23 合并k个升序链表

问题描述

给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
在这里插入图片描述

解题思路

这个题的最基础的思路就是合并有序链表,和21题方法是一样的,难点在于现在的链表数是k个,而不是简单的两个。首先最自然可以想到的就是按顺序合并给定的k个链表,其次就是有点归并排序的思想,用分治法。

分治法

自底向上归并,第一次归并2个链表,第二次归并4个链表,以此类推,每次归并不断合并两个有序链表,直到合并完所以分治后的链表。代码如下:

var mergeKLists =function(lists){
	//数组为空的情况
	if(!lists.length){
		return null;
	}
	//合并两个列表
	const merge=(head1,head2)=>{
		let dummy=new ListNode(0);
		let cur=dummy;
		//新的链表,谁小就先接谁
		while(head1&&head2){
			if(head1.val<=head2.val){
				cur.next=head1;
				head1=head1.next;
			}else{
				cur.next=head2;
				head2=head2.next;
			}
				cur=cur.next;
		}
			/*while(head1){
				cur.next=head1;
				head1=head1.next;
				cur=cur.next;
			}
			while(head2){
				cur.next=head2;
				head2=head2.next;
				cur=cur.next;
			}*/
			cur.next=head1==null?head2:head1;
			return dummy.next;
		};
		const mergeLists=(lists,start,end)=>{
			if(start+1==end){
				return lists[start];
			}
			//输入的k个排序链表,可以分为两个部分,前k/2个链表和后k/2个链表
			//如果将这前k/2个链表和后k/2个链表分别合并成两个排序的链表,再将两个排序的链表合并,那么所有链表都合并了
			let mid=(start+end)>>1;
			let head1=mergeLists(lists,start.mid);
			let head2=mergeLists(lists,mid,end);
			return merge(head1,head2);
		};
		return mergeLists(lists,0,lists.length);
	};
	
//自底向上合并
var mergeKLists=function(lists){
//当归并的节点只有一个时,返回这个节点
	if(lists.length<=1) return lists[0]||null;
	const newLists=[];
	//自底向上归并,第一次归并大小为2的链表,第二次归并大小为4的链表....
	for(let i=0;i<lists.length;i+=2){
		newLists.push(merge(lists[i],lists[i+1]||null));
	}
		return mergeKLists(newLists);
};
const merge=(list_1,list_2)=>{ //合并两个有序链表
	const dummyNode=new ListNode(0);
	let p=dummyNode;
	while(list_1&&list_2){
		if(list_1.val<=list_2.val){
			p.next=list_1;
			list_1=list_1.next;
		}else{
			p.next=list_2;
			list_2=list_2.next;
		}
		p=p.next;
	}
	p.next=list_1?list_1:list_2;
	return dummyNode.next;
};
优先队列

这个看到别人的思路,用最小堆做的,我先偷个懒,之后再看。还看到有先把值取出来再新建链表的,属于是直接逃了,略过面试官期待的解法哈哈哈哈。

二、 24 两两交换链表中的节点

问题描述

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
在这里插入图片描述

解题思路

第一个简单的思路就是先对原链表做拆分,第1、3、5…个元素作为一个单独的队列,第2、4、6…元素作为一个单独的队列,然后再将偶数位置的数列作为前置数列拼接起来。但是这样需要设置很多的指针,代码实现也比较复杂,所以转换为采用递归的思想。
递归结束的条件就是列表中没有元素或者只含有一个元素,递归内部的操作就是对元素进行互换,原来的头节点head变为列表中的第二个节点,原来的第二个节点是新的头节点newhead。newhead.next=head,head.next=swapPairs(newHead.next)。代码如下:

var swapPairs = function(head) {
    if(!head||!head.next) return null||head;
    let newHead=head.next;
    head.next=swapPairs(newHead.next);
    newHead.next=head;
    return newHead;
};

还有一种就是直接做调换,这里需要特别注意要从调换的前一个位置开始记录指针,不然链表会断开的。具体代码如下:

var swapPairs=function(head){
 	if(!head||!head.next) return head||null;
 	let dummyhead=new ListNode(0,head);
 	let temp=dummyhead;
 	while(temp.next!=null&&temp.next.next!=null){
 		let n1=temp.next;
 		let n2=temp.next.next;
 		temp.next=n2;
 		n1.next=n2.next;
 		n2.next=n1;
 		temp=n1;
 	}
 	return dummyhead.next;
 };

82 删除排序链表中重复的元素

问题描述

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
在这里插入图片描述

解题思路

虚拟头节点+双指针

首先初始化哑节点dummyhead的next指向head,初始化快慢指针fast、slow的值分别为dummyhead、head;fast指针用来寻找重复节点,只要fast和fast.next值相等,fast则向后移动;slow.next=fast.next删除重复值,最后返回dummyhead.next;

var deleteDuplicates=function(head){
//防止删除头节点,所以设置一个哑节点
if(!head||!head.next) return head||null;
const dummyhead=new ListNode(0,head);
let fast=dummyhead.next,slow=dummyhead;
while(fast){
	while(fast.next!==null&&fast.val==fast.next.val) fast=fast.next;
	if(slow.next==fast){
		slow=slow.next;
	}else{
		slow.next=fast.next;
	}
	fast=fast.next;
	}
	return dummyhead.next;
}
递归

A、终止条件:
1、若head为空,则肯定没有值出现重复的节点,直接返回head;
2、若head.next为空,说明链表中只存在一个节点,也不可能出现重复的节点,可直接返回head;
B、如果head.val!=head.next.val,说明头节点的值不等于下一个节点的值,所以当前的head节点必须保留,但是head.next的节点是否需要保留还不确定,需要对head.next进行递归,即对以head.next为头节点的链表进行去除重复值的操作,所以head.next=self.deleDuplicates(head.next);
C、如果head.val==head.next.val,说明头节点的值对于下一个节点的值,所以当前head节点必须删除,并且之后和head.val相等的节点也都需要删除,直到找到与head.val不等的节点,在这里需要设置一个move指针来向后遍历寻找这个不等的节点。此时move之前的系欸但都不要保留,只返回deleDuplicates(move);

var deleteDuplicates=function(head){
	if(head==null||head.next==null) return head;
	if(head.next.val==head.val){
		let temp=head.next;
		while(temp!=null&&head.val==temp.val)
		temp=temp.next;
		return deleteDuplicates(temp);
		}else{
			head.next=deleteDuplicates(head.next);
		}
		return head;
	};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习JavaScript算法非常重要,因为它是一种用于解决问题的编程语言。通过学习JavaScript算法,我们可以更加了解数据结构、算法和编程逻辑。 首先,我们需要掌握JavaScript基本语法和语法规则。了解如何声明变量、使用条件语句、循环语句和函数等是非常重要的。这些知识将为我们编写算法提供基础。 其次,我们需要了解常见的算法和数据结构。学习排序算法(如冒泡排序、快速排序)、搜索算法(如二叉搜索树、哈希表)以及链表、队列和栈等数据结构。这些算法和数据结构是解决问题的重要工具。 在学习算法时,我们要注重正确性和效率。我们应该注意算法的时间复杂度和空间复杂度,力求编写出高效的算法。此外,我们还可以学习一些优化技巧,如贪心算法和动态规划,以提高算法的效率。 除了学习传统的算法和数据结构之外,我们还可以学习一些JavaScript特定的算法。例如,学习如何使用递归、闭包和高阶函数来解决问题。这些JavaScript特性可以帮助我们编写更加简洁和灵活的算法。 最后,为了加深对算法的理解和应用,我们可以尝试解决一些经典的算法问题。这些问题可以帮助我们锻炼思维能力和编程技巧。解决这些问题将使我们能够更好地应对实际中的问题。 总之,学习JavaScript算法是程序员的必备技能之一。通过掌握基本语法、常见算法和数据结构,以及考虑正确性和效率,我们将能够写出高质量的JavaScript代码,并更好地解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值