🚝1. 删除链表中的节点
题目解析 观察到题目给定的参数只有一个节点,且该节点非末尾,可以把该节点的下一节点直接连到下下个节点上,再将值改为下一个节点的值。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void deleteNode(ListNode node) {
ListNode nextNode=node.next;
node.next=nextNode.next;
node.val=nextNode.val;
}
}
🚝2.删除链表的倒数第N个节点
题目解析 这题解题的关键是首先 在链表头再定义一个呀哑节点 然后可以观察题目得到我们需要计算链表长度L,然后删除倒数第n个其实是删除从列表开头数起的第 (L-n+1)个结点。可以从哑节点遍历到,待删除的节点前一个节点,将该节点的下一个节点定义为待删除节点的下一个节点。 哑节点的目的就是为啥删除第一个节点。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode first=head;
int length=0;
while(first!=null){
length++;
first=first.next;
}
length=length-n;
first=dummy;
for(int i=0;i<length;i++){
first=first.next;
}
first.next=first.next.next;
return dummy.next;
}
}
🚝3.反转链表
方法一
定义两个指针:b和a ;a为null,b为链表第一项
每次让 b 的 next 指向 a ,实现一次局部反转
局部反转完成之后, a 和 b 同时往前移动一个位置,a 移动到 b 的位置,b 则移动到一下项,循环上述过程,直至 a 到达链表尾部
双指针代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null){return null;}
ListNode a=null;
ListNode b=head;
while(b!=null){
ListNode c=b.next;
b.next=a;
a=b;
b=c;
}
return a;
}
}
方法二 递归找到链表的最后一个结点,该结点是反转后的头结点 ,每次函数在return前,让当前结点的下一个结点的 next 指针指向当前节点。让当前结点的next指针指向null ,从而实现从链表尾部开始的局部反转。
递归函数全部出栈后,链表反转完成。
代码
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){return head;}
ListNode ret=reverseList(head.next);
head.next.next=head;
head.next=null;
return ret;
}
}
🚝4.合并两个有序链表
题目解析 因为两个链表有序,所以可以定义同时遍历两个链表,将比较小的节点拿出来连接成新的链表
代码
/**
* 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 mergeTwoLists(ListNode l1, ListNode l2) {
//定义一个新链表
ListNode result=new ListNode(0);
//flag记录新链表头节点
ListNode flag=result;
while(l1!=null&&l2!=null){
if(l1.val<=l2.val){result.next=l1;result=result.next;l1=l1.next;}
else if(l1.val>l2.val){result.next=l2;result=result.next;l2=l2.next;}
}
if(l1==null){while(l2!=null){result.next=l2;result=result.next;l2=l2.next;}}
if(l2==null){while(l1!=null){result.next=l1;result=result.next;l1=l1.next;}}
return flag.next;
}
}
🚝5.回文链表
题目解析 直接将链表取出得到数组,双指针判断是否回文数组。
❗值得注意的是在比较int类型的数据时,使用equals而不是==,因为超过-128~128的int型数据需要new而不是从常量池取,所以地址不同。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
List<Integer> array=new ArrayList<Integer>();
while(head!=null){
array.add(head.val);
head=head.next;
}
int i=0;
int j=array.size()-1;
while(i<j){
if(!array.get(i).equals(array.get(j))){return false;}
i++;j--;
}
return true;
}
}
🚝6.环形链表
题目解析 遍历链表,并将遍历过的节点放入set集合,当set出现重复节点说明链表有环
代码
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> set=new HashSet<ListNode>();
while(head!=null){
if(set.contains(head)){return true;}
set.add(head);
head=head.next;
}
return false;
}
}
🚝7.反转链表 II
题目解析 首先找到需要反转部分的头部left
与尾部right
,头部前置节点preleft
,头部的下一个节点nextleft
用于反转。
使用双指针将这一部分链表反转,然后将头部前置节点preleft
的next设置为反转后的头部,反转后的尾部的next设置为原来尾部后置节点(双指针反转后可得到)
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
boolean flag=false;
if(head==null){return null;}
if(n==1){return head;}
if(m==1){flag=true;}
ListNode left=head;
ListNode right=head;
ListNode preleft=null;
int time=n-m;
while(m-1>0){
preleft=left;
left=left.next;
m--;
}
ListNode begin=left;
ListNode nextleft=left.next;
while(n-1>0){
right=right.next;
n--;
}
if(flag){head=right;}
for(int i=0;i<time;i++){
ListNode temp=nextleft.next;
nextleft.next=left;
left=nextleft;
nextleft=temp;
}
begin.next=nextleft;
if(preleft!=null)preleft.next=left;
return head;
}
}