赞
踩
问题需求:根据给定的val值,移除链表中值是这个val的节点
这里有一个问题就是,如果需要被移除的节点不是中间的某个节点,而是头节点。就没法借助前一个节点了,而是直接将
head = head.next
所以有两种思路,要么是分类处理;要么是在原本的head节点前面增加一个虚拟头节点,这样头节点也有个前面的节点了
还有需要注意的是,这里的代码,不应该用if,因为我们是一直移除的一个过程,所以应该用while
public ListNode removeElements(ListNode head, int val) {
while(head != null && head.val == val) //之所以不用if,是因为可能从头结点开始有连续的等于val的节点
head = head.next;
ListNode cur = head; //删除非头节点情况
while(cur != null && cur.next != null){
if(cur.next.val = val)
cur.next = cur.next.next;
else
cur = cur.next;
}
return head;
}
ListNode dummyHead = new ListNode(0); // 设置⼀个虚拟头结点
dummyHead.next = head; // 将虚拟头结点指向head,这样⽅⾯后⾯做删除操作
ListNode cur = dummyHead;
while(cur.next != null){
...
}
return dummyHead.next;
就是实现关于链表的各个操作,为了方便,还是用上了虚拟头节点
初始化中的0就是虚拟头节点了
双指针法
遍历链表,按照头插法,将旧链表的一个个节点放到新链表的头节点,最后反转成功
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode first = null;
while(cur!=null){
ListNode tmp = cur.next; // 保存⼀下 cur的下⼀个节点,因为接下来要改变cur->next
cur.next = first; //头部插入
//更新双指针
first = cur;
cur = tmp;
}
return first;
}
需要借助虚拟头节点,这样操作会简单一点
每次需要一个指针cur指向需要被交换的两个节点,的前一个节点
顺序就是,虚拟头节点先指向2,然后让2指向1,最后1指向3。而这里的“1”和“3”是需要两个临时节点记录一下
public ListNode swapPairs(ListNode head) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur = dummyHead;
while(cur.next != null && cur.next.next != null){
ListNode tmp = cur.next;
ListNode tmp1 = cur.next.next.next;
cur.next = cur.next.next;
cur.next.next = tmp;
cur.next.next.next = tmp1;
cur = tmp; // 或者cur = cur.next.next; cur移动两位,准备下⼀轮交换
}
return dummyHead.next;
}
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
由于需要删除的是倒数第N个,所以可以用快慢指针
双指针的经典应⽤,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了
这里需要注意的就是,需要虚拟头节点,考虑到了如果链表只有一个元素,或者只有两个元素的情况
这种时候,用到虚拟头节点,就很好的可以处理
另外,最后返回的时候,不要返回head,而是返回dummyhead.next,因为如果只有一个节点的情况,删除后,就没有head,就知识null了,所以不能返回head
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode fast = dummyhead;
ListNode slow = dummyhead;
for(int i = 0; i < n; i++)
fast = fast.next;
fast = fast.next; // fast再提前⾛⼀步,因为需要让slow指向删除节点的上⼀个节点
while(fast != null){
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return dummyhead.next; //不能返回head,只能是dummyhead.next
}
面试题 02.07. 链表相交 - 力扣(LeetCode)
其实这个链表问题主要需要总结的就是那些经验及方法,而对于两个无环结构的链表,就是常规方法
先是求出连两个链表的长度length1,length2,然后就是需要判断这两个链表的尾结点是不是一样的
如果连尾结点都不一样,就说明两个链表连一个结点都没有重合,所以两个链表绝对不会重合
如果尾结点一样的话,需要将两个链表的长度互减
然后这个数num的绝对值就是这两个链表长度的差值,**让长链表提前走num步,然后两个链表再同时走,**直到遇见了相同的交点处停下来返回此结点,具体代码如下:
public static Node noLoop(Node head1, Node head2) { if (head1 == null || head2 == null) { return null; } Node cur1 = head1; Node cur2 = head2; int n = 0; //这里为了简化以及节省空间,就设置了一个变量n,通过下面的两个while循环,一个自加,一个自减,最后求他的绝对值,就是两个链表的长度差值 while (cur1.next != null) { n++; cur1 = cur1.next;} while (cur2.next != null) { n--; cur2 = cur2.next;} if (cur1 != cur2) { //如果最后一个结点都不一样,那么两个链表绝对不可能有交合的地方了 return null; } cur1 = n > 0 ? head1 : head2; //谁长,谁的头变成cur1 cur2 = cur1 == head1 ? head2 : head1; //谁短,谁的头变成cur2 n = Math.abs(n); while (n != 0) { //先让长链表走了n步 n--; cur1 = cur1.next; } while (cur1 != cur2) { //开始寻找相交结点 cur1 = cur1.next; cur2 = cur2.next; } return cur1; }
划分为两个问题:
判断链表是否有环,可以借助哈希表set,也可以用快慢指针,
**1)哈希表set:**将所有节点放进set中,每放进去一个节点都查查这个节点是不是在集合中,第一次查到这个节点在集合中的时候,就说明这个节点就是环的起点
2)快慢指针: 只要最后不会指向空【如果快指针指向空了,就说明没有环】,并且快慢指针重合,就说明该链表又环。判断有环之后,就要开始找环的起始点,看下面的描述
//哈希表set public static boolean hasCycle(Node head){ HashSet<Node> set = new HashSet<Node>(); set.add(head); Node cur = head.next; while(true){ if(set.contains(cur)) return true; else{ set.add(cur); cur=cur.next; if(cur==null) return false; } } }
//快慢指针
public static boolean ifCycle(Node head){
Node slow = head;
Node fast = head.next;
while(fast != slow){
if(fast == null)
return false;
slow = slow.next;
fast = fast.next.next;
}
return true;
}
这里一开始还是借助快慢指针,先是判断有无环结构:
如果有环的话,也就是说快慢指针在环上的某一个结点上重合了。(这是第一个while循环)
此后就到了本方法的骚气处了【这是通过公式推导出来的规律!!记住这个结论!!!】
public ListNode detectCycle(ListNode head) { ListNode fast = head; ListNode slow = head; while(fast != null && fast.next != null){ fast = fast.next.next; slow = slow.next; if(slow == fast) break; } if(fast == null || fast.next == null) //跳出上面循环时有两种可能,一是没有环,另外就是slow == fast。所以需要判断如果 //无环的话,直接返回null return null; fast = head; while(fast != slow){ fast = fast.next; slow = slow.next; } return fast; }
借助栈
public static boolean isPalindrome1(Node head) {
Stack<Node> s = new Stack<Node>();
Node cur = head;
while(cur != null){
s.push(cur);
cur = cur.next;
}
cur = head;
while(head != null){
if(head.val != s.pop().val)
return false;
head = head.next;
}
return true;
}
本文是基于学习代码随想录,以及自刷leetcode总结链表方面的笔记,不仅仅限于代码随想录笔记,是一些自己的思考和整理。并且是Java版本
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。