在上一条博客中我们已经介绍一些关于自己实现的单链表的基础操作,接下来我们基于上条博客的代码再写一些单链表的进阶的操作方法:
1.给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 :
输入: 1->1->2
输出: 1->2
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode cur=head;
ListNode node=new ListNode(-1);
ListNode temp=node;
while(cur!=null){
if(cur.next!=null&&cur.val==cur.next.val){
while(cur.next!=null&&cur.val==cur.next.val){
cur=cur.next;
}
}else{
temp.next=cur;
temp=temp.next;
cur=cur.next;
}
}
//尾结点
temp.next=null;
return node.next;
}
}
2.定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode pre=null;
ListNode newHead=head;
while(cur!=null){
ListNode Next=cur.next;
if(cur.next==null){
newHead=cur;
}
cur.next=pre;
pre=cur;
cur=Next;
}
return newHead;
}
}
3.输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。
示例:
给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if(k<=0||head==null){
return null;
}
ListNode fast=head;
ListNode slow=head;
while(k-1>0){
if(fast.next!=null){
fast=fast.next;
k--;
}else{
return null;
}
}
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
4.编写一个函数,检查输入的链表是否是回文的。
示例 1:
输入: 1->2
输出: false
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if(head==null){
return true;
}
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
ListNode cur=slow.next;
while(cur!=null){
ListNode curNext=cur.next;
cur.next=slow;
slow=cur;
cur=curNext;
}
while(slow!=head){
if(slow.val!=head.val){
return false;
}
if(head.next==slow){
return true;
}
slow=slow.next;
head=head.next;
}
return true;
}
}
5.编写程序以 x 为基准分割链表,使得所有小于 x 的节点排在大于或等于 x 的节点之前。如果链表中包含 x,x 只需出现在小于 x 的元素之后(如下所示)。分割元素 x 只需处于“右半部分”即可,其不需要被置于左右两部分之间。
示例:
输入: head = 3->5->8->5->10->2->1, x = 5
输出: 3->1->2->10->5->5->8
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode bs=null;
ListNode be=null;
ListNode as=null;
ListNode ae=null;
ListNode cur=head;
while(cur!=null){
if(cur.val<x){
if(be==null){
bs=cur;
be=cur;
}else{
be.next=cur;
be=be.next;
}
}else{
if(ae==null){
as=cur;
ae=cur;
}else{
ae.next=cur;
ae=ae.next;
}
}
cur=cur.next;
}
if(as!=null){
ae.next=null;
}
if(bs==null){
return as;
}
be.next=as;
return bs;
}
}
6.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 :
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
}
7.将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newHead=new ListNode(-1);
ListNode temp=newHead;
while(l1!=null&&l2!=null){
if(l1.val<l2.val){
temp.next=l1;
l1=l1.next;
temp=temp.next;
}else{
temp.next=l2;
l2=l2.next;
temp=temp.next;
}
}
if(l1!=null){
temp.next=l1;
}
if(l2!=null){
temp.next=l2;
}
return newHead.next;
}
}
8.输入两个链表,找到他们的第一个公共节点.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null||headB==null){
return null;
}
int len1=0;
int len2=0;
ListNode pL=headA;
ListNode ps=headB;
while(pL!=null){
len1++;
pL=pL.next;
}
while(ps!=null){
len2++;
ps=ps.next;
}
//如果不指回来 就是空了
pL=headA;
ps=headB;
int len=len1-len2;
if(len<0){
pL=headB;
ps=headA;
len=len2-len1;
}
//可以保证:
//1.pL指向长的单链表 ps指向短的
while(len>0){
pL=pL.next;
len--;
}
//
while(pL!=null&&ps!=null&&pL!=ps){
ps=ps.next;
pL=pL.next;
}
if(pL!=null&&ps!=null&&pL==ps){
return pL;
}
return null;
}
}
9.给定一个链表,判断链表中是否有环。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 :
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
/**
* 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) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
break;
}
}
if(fast==null||fast.next==null){
return false;
}
return true;
}
}
10.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 :
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
/**
* 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) {
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
break;
}
}
if(fast==null||fast.next==null){
return null;
}
slow=head;
while(fast!=slow){
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
以上就是基于链表的一些常见进阶操作 在明天的博客我们将会自己实现一个顺序表~