24. 两两交换链表中的节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
//如果链表为空 或者链表只存在头结点 就直接返回
if(head==null || head.next==null){
return head;
}
ListNode fakeHead=new ListNode();
fakeHead.next=head;
ListNode prePreNode=new ListNode();
prePreNode=fakeHead;
//这个循环判断语句是为了判断偶数结点链表两两交换到底了 或者 奇数链表的情况
while(prePreNode.next!=null && prePreNode.next.next!=null){
//始终用prePreNode记录要被交换的两个节点的前一个节点。
//swapedFormerNode 要被两两交换的两个节点的第一个节点
//swapedLatterNode 要被两两交换的两个节点的第二个节点
ListNode swapedFormerNode= prePreNode.next;
ListNode swapedLatterNode=swapedFormerNode.next;
//两两交换操作
prePreNode.next=swapedLatterNode;
swapedFormerNode.next=swapedLatterNode.next;
swapedLatterNode.next=swapedFormerNode;
//prePreNode更新,继续指向下一对两两交换的节点的上一个结点
prePreNode=prePreNode.next.next;
}
return fakeHead.next;
}
}
19.删除链表的倒数第N个节点
具体代码
方法一:获取链表长度
思路:
先通过遍历获取整个链表的长度,然后将length-n作为遍历的基准条件,以此来遍历得到要被删除的节点的上一个结点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//统计链表长度
ListNode fakeHead=new ListNode();
fakeHead.next=head;
int len=0;
ListNode temp=fakeHead;
while(temp.next!=null){
temp=temp.next;
len++;
}
//找到要被删除结点的上一个结点
ListNode pre = fakeHead;
int count=0;
while(count!=len-n){
pre=pre.next;
count++;
}
//删除操作
pre.next=pre.next.next;
return fakeHead.next;
}
}
方法二:快慢指针
单链表中的所有删除操作,一定一定是要找到被删除结点的上一个结点。
(在使用虚拟头结点的基础上)通过模拟,可以发现,如果让快指针先走n步,而后快慢节点再同时出发,当快结点到最后null时,此时慢节点正好指向要被删除的倒数第n个结点。
但是为了让slow慢结点指向倒数第n个结点的上一个结点,fast结点就要多走一步,即n+1步。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fakeNode=new ListNode();
fakeNode.next=head;
//初始时,slow和fast指针都指向虚拟头结点
ListNode slow=fakeNode;
ListNode fast=fakeNode;
//将快指针往前移动n+1个结点
for(int i=0;i<n+1;i++){
fast=fast.next;
}
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return fakeNode.next;
}
}
142.环形链表II
具体代码
暴力解法
实在想不出别的,目前只想出来暴力解法。极其之暴力。使用了很多空间以及时间。(但是leetcode能通过)
至于更加优雅的算法,参考carl哥,但是目前个人尚不能理解。故不贴
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
//暴力解法
//map用于记录哪些节点已经访问过了
Map<ListNode,Integer> map=new HashMap<>();
if(head==null || head.next==null){
return null;
}
//通过上面if语句的排除 可以知道目前的链表最少最少也有两个结点
ListNode current= head;
ListNode temp=current;
while(true){
map.put(temp,1); //把当前节点放入map中 代表已经遍历过了
//temp指向下一个
temp=temp.next;
//无环
if(temp.next==null){
return null;
}
//只要这个结点已经被遍历过了,那么它肯定是环的起点!!!
if(map.containsKey(temp)){
return temp;
}
}
}
}