每晚22:00更新,不更新胖十斤
欢迎大家一起刷题~
题目均来自 牛客网 以及 LeetCode
1.反转链表(NC78、Leetcode#206)
反转一个单链表
示例:
- 输入: 1->2->3->4->5->NULL
- 输出: 5->4->3->2->1->NULL
解答:
var reverseList = function(head) { if(!head||!head.next) return head var pre = null,cur = head while(cur){ var temp = cur.next cur.next = pre pre = cur cur = temp } head = pre return head };
2.两个链表的第一个公共节点(NC66、Leetcode剑指offer52、Leetcode#160)
输入两个链表,找出它们的第一个公共节点
分析:
- 双指针法
- 假设两个链表的长度相同,此时使用双指针(每个链表使用一个指针)从头到尾的比较,遇到第一个相同的节点则直接返回
- 不管两个链表各自的长度是多少,只要两个链表相加,则会得到两个长度相同的链表,此时在使用双指针即可返回
- 实现相加的方式即为从头到尾扫描链表,扫描到当前链表的最后一个节点时,指向另一个链表的头节点,从而达到相加的效果
- 伪代码:
- 1.分别保存两个链表的头指针
- 2.循环判断两个头指针是否不相等,相等则退出循环
- 3.循环内则进行双指针判断(每个指针进行比较是否为空,不为空则指向下一节点,为空则指向另一链表头节点)
- 双指针法
解答:
var getIntersectionNode = function(headA, headB) { var cur1 = headA,cur2 = headB while(cur1 != cur2){ cur1 = cur1 ? cur1.next : headB cur2 = cur2 ? cur2.next : headA } return cur1 };
3.合并两个有序链表(NC33)
将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的
分析:
- 两个列表长度可能不同,所以只需要比较较短的链表和另一链表每个节点的大小
- 循环比较,出现节点为null时则比较结束
- 头节点此时需要判断那个链表的节点为空,则将头指向另一个链表的剩余部分
- 返回新头节点
- 伪代码:
- 1.分别保存两个链表的头指针
- 2.循环判断两个头指针是否不相等,相等则退出循环
- 3.循环内则进行双指针判断(每个指针进行比较是否为空,不为空则指向下一节点,为空则指向另一链表头节点)
解答:
/* * function ListNode(x){ * this.val = x; * this.next = null; * } */ /** * * @param l1 ListNode类 * @param l2 ListNode类 * @return ListNode类 */ function mergeTwoLists( l1 , l2 ) { if(l1 == null || l2 == null) return l1 == null? l2 : l1 //将每个链表的头节点的值进行保存 var head1 = l1.val,head2 = l2.val //比较两头节点,取小的为新链表头节点 var newHead = head1<=head2?l1:l2 //新尾结点 var tail = newHead //找到新头节点是哪个链表的头,找到的哪个指针后移,另一个则保持不变 l1 = (newHead == l1)? l1.next:l1; l2 = (newHead == l2)? l2.next:l2; while(l1 != null && l2 != null){ //比较较小的节点,将它插入新列表的尾 if(l1.val<=l2.val){ tail.next = l1 l1 = l1.next }else{ tail.next = l2 l2 = l2.next } //插入完成后,尾后移 tail = tail.next } //循环结束后一定有一个列表已经全部被比较完,此时指定新尾结点的指向 //因为两个链表长度不一致,可能出现一个已经轮空,另一个还有节点的情况 //此时,新链表尾节点应指向此时不为空的链表,因为每个链表都是有序的,所以不需要在对剩余节点进行排序 tail.next = l1==null?l2:l1 return newHead } module.exports = { mergeTwoLists : mergeTwoLists };
4.合并K个有序链表(NC51、Leetcode#23)
合并 k 个已排序的链表并将其作为一个已排序的链表返回。分析并描述其复杂度。
分析:
- 合并两个有序链表 + 将给定K个列表进行遍历,两个两个调用合并两个有序链表
- 伪代码:
- 1.遍历lists,一个一个合并
- 2.合并的核心方法还是双指针,与合并两个有序列表一样
解答:
/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } */ /** * @param {ListNode[]} lists * @return {ListNode} */ var mergeKLists = function(lists) { //最笨方法 //1.遍历lists,一个一个合并 //2.合并的核心方法还是双指针,与合并两个有序列表一样 const mergeTwoLists = (l,r)=>{ if(l==null||r==null) return l==null?r:l var head = l.val<=r.val?l:r var tail = head l = l==head ? l.next : l r = r==head ? r.next : r while(l&&r){ if(l.val<=r.val){ tail.next = l l = l.next }else{ tail.next = r r = r.next } tail = tail.next } tail.next = !l ? r : l return head } var res = lists[0] if(lists.length==0) return null for (let i = 1;i<lists.length;i++){ if(lists[i]){ res = mergeTwoLists(res,lists[i]) } } return res };
5.删除链表中的倒数第N个节点(NC53)
给定一个链表,删除链表的倒数第n个节点并返回链表的头指针
给出的链表为:1->2->3->4->5, n= 2. 删除了链表的倒数第n个节点之后,链表变为1->2->3->5分析:
- 找到删除的节点位置,并将这个指针指向他的下下个结点
- 需要声明三个链表变量,第一个用来遍历得出链表长度,第二个用来进行删除操作,第三个用来返回结果,复制第二个链表
- 伪代码:
- 1.遍历一遍链表,得到链表长度
- 2.根据数组长度循环得到删除的节点,循环长度为链表长度-删除的个数-1
- 3.循环外进行断指针操作,将找到的删除节点进行删除操作
- 4.返回
解答:
function removeNthFromEnd( head , n ) { var new = head,tail = head,res = tail,length = 0 //获取链表长度 while(new!=null){ length++ new = new.next } if(length-n==0){ //链表只有一个结点,直接删除,返回删除后的节点 res = res.next return res } for(let i =0;i<length-n-1;i++){ tail = tail.next//将指针移到需要删除的节点的前一个 } tail.next = tail.next.next return res } module.exports = { removeNthFromEnd : removeNthFromEnd };
6.判断链表中是否有环(NC4)
判断给定的链表中是否有环
分析:
- 快慢指针法
- 声明两个指针,一个快一个慢,判断快指针,如果快指针直接null则肯定没有环
- 伪代码:
- 1.判断头节点,头的next,头的next.next有一个为空就不可能有环
- 2.声明快慢指针
- 3.循环快指针且快指针的下个结点都不为空,快慢指针一直移动,等到快慢指针如果相等,则有环
- 4.返回
解答:
/* * function ListNode(x){ * this.val = x; * this.next = null; * } */ /** * * @param head ListNode类 * @return bool布尔型 */ function hasCycle( head ) { if(head==null||head.next==null||head.next.next==null)return false var slow = head,fast = head //必须判断快指针,如果快指针直接null则肯定没有环 while(fast!=null&&fast.next!=null){ fast = fast.next.next slow = slow.next if(fast==slow)return true } return false } module.exports = { hasCycle : hasCycle };
更新时间 2020-09-10 21:36
7.判断链表中是否有环(NC96)
给定一个链表,请判断该链表是否为回文结构
分析:
- 思路为将链表每个节点的值保存至数组,数组前后比较是否相等,出现不等时,直接返回false
- 伪代码:
- 1.保存head节点cur,声明变量存放新建数组nodeArr=[],新建数组长度len,以及数组下标i
- 2.循环判断cur不指向空,将链表节点值push进数组
- 3.循环判断数组左侧下标小于右侧下标时,在判断左侧下标值是否等于右侧,不等于,返回false;i++
- 4.否则返回true
解答:
/* * function ListNode(x){ * this.val = x; * this.next = null; * } */ /** * * @param head ListNode类 the head * @return bool布尔型 */ function isPail( head ) { // write code here //前后两个指针,一个一个比对,一旦不相等 则return var cur = head,nodeArr = [] while(cur!=null){ nodeArr.push(cur.val) cur = cur.next } var len = nodeArr.length,i = 0 while(i<len-i-1){ if(nodeArr[i]!==nodeArr[len-i-1]){ return false } i++ } return true } module.exports = { isPail : isPail };