一、快慢指针
与环有关、倒数第k个节点
链表中环的入口地址
思路1:慢指针p1,快指针p2,当p2!=null or p2.next!=null, p1每次走一步,p2每次走两步,当p1=p2,到达相遇点
然后p2从链表头开始,p1继续从相遇点走,以相同速度走,下次相遇时就是链表的入口
思路2:创建set,如果节点不为空,则循环,节点不在set中,则加入;在set中,说明已经循环了,为入口点,返回该节点
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
if pHead is None:
return None
p1=pHead
p2=pHead
while(p2!=None and p2.next!=None):
p1=p1.next
p2=p2.next.next
if p1==p2:
p2=pHead
while(p1!=p2):
p1=p1.next
p2=p2.next
if p1==p2:
return p1
return None
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead==null || pHead.next==null) return null;
ListNode p1=pHead;
ListNode p2=pHead;
while(p2!=null && p2.next!=null){
p1=p1.next;
p2=p2.next.next;
if(p1==p2) {
p1=pHead;
while(p1!=p2){
p1=p1.next;
p2=p2.next;
}
if(p1==p2)
return p1;
}
}
return null;
}
}
链表中倒数第k个结点
思路一:
*两个指针fast和slow,让两个指针都指向头结点;
*让fast走(k-1)步(1~k-1),到达第k个节点;
*两个指针同时往后移动,当fast到达末尾的时候,slow所在位置就是倒数第k个结点
注意 head为空,k<=0;以及节点.next 为空的判断
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head==null || k<=0) return null;
ListNode fast=head;
ListNode slow=head;
for(int i=1;i<=k-1;i++){
if(fast.next!=null){//判断
fast=fast.next;
}
else return null;
}
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindKthToTail(self, head, k):
# write code here
if head==None or k<=0:
return None
slow=head
fast=head
for i in range(1,k):
if fast.next!=None:
fast=fast.next
else:
return None
while(fast.next!=None):
fast=fast.next
slow=slow.next
return slow
求链表的中间节点。
如果链表中结点总数为奇数,返回中间结点;如果结点总数是偶数,返回中间两个结点的任意一个。
解法: 定义两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步。
当走得快的指针走到链表的末尾时,走得慢的指针正好在链表的中间。
二、利用列表/HashMap/stack等存储转换
两个链表的第一个公共节点
思路1:利用列表或者hashmap
step1:遍历存入pHead1的节点,python list存值,Java hashmap存节点,
step2:然后遍历pHead2看是否在pHead1的列表(值),hashmap(节点)中
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
list1=[]
node1=pHead1
node2=pHead2
while node1:
list1.append(node1.val)
node1=node1.next
while node2:
if node2.val in list1:
return node2
else:
node2=node2.next
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
import java.util.HashMap;
import java.util.Map;
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if (pHead1 == null || pHead2 == null) return null;
Map<ListNode, Integer> map = new HashMap<>();
while (pHead1 != null)
{
map.put(pHead1, null);
pHead1 = pHead1.next;
}
while (pHead2 != null)
{
if (map.containsKey(pHead2)) return pHead2;
else pHead2 = pHead2.next;
}
return pHead2;
}
}
思路二:p1和p2向后移动,短的p1移到末尾,p1从长链表list2头部继续,当p2到达尾部,p2从短链表list1开始,如果能p1==p2则为第一个公共节点,没有则退出
假定:List1长度: a+n,List2长度:b+n, 且 a<b
那么,p1会先到链表尾部,这时p2走到a+n位置,将p1换成List2头部。
接着,p2 再走b+n-(n+a) =b-a步到链表尾部,这时p1也走到List2的b-a位置,还差a步就到可能的第一个公共节点。
将p2换成 List1头部,p2走a步也到可能的第一个公共节点。
如果恰好p1==p2,那么p1就是第一个公共节点。
或者p1和p2一起走n步到达列表尾部,二者没有公共节点,退出循环。
同理a>=b。
时间复杂度O(n+a+b)
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null || pHead2==null)
return null;
ListNode p1=pHead1;
ListNode p2=pHead2;
while(p1!=p2){
p1=(p1==null)?pHead2:p1.next;
p2=(p2==null)?pHead1:p2.next;
}
return p1;
}
}
从尾到头打印链表
栈,列表反转
思路一:创建一个list,将链表值加入;然后反转输出
python
# -*- coding:utf-8 -*-
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
resultlist=[]
while listNode:
resultlist.append(listNode.val)
listNode=listNode.next
resultlist.reverse()
return resultlist
JAVA三种方式
思路一:利用Collections的reverse方法,类似python
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> res = new ArrayList<>();//创建res
while (listNode != null)//!=null
{
res.add(listNode.val);
listNode = listNode.next;
}
Collections.reverse(res);//利用Collections对res反转
return res;
}
}
思路二:借助堆栈的“后进先出”实现
先将元素存入堆栈;再取出堆栈中元素存入数组列表
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> nums = new Stack<>();
while (listNode != null)
{
nums.push(listNode.val);
listNode = listNode.next;
}
ArrayList<Integer> res = new ArrayList<>();
while (!nums.isEmpty())
res.add(nums.pop());
return res;
}
}
思路三:借助递归实现(递归的本质还是使用了堆栈结构)
import java.util.ArrayList;
public class Solution {
ArrayList<Integer> res = new ArrayList<>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ListNode pNode = listNode;
if (pNode != null)
{
if (pNode.next != null)
this.printListFromTailToHead(pNode.next);
res.add(pNode.val);
}
return res;
}
三、链表结构更改
反转链表
思路一:非递归
*head为空时,直接返回null;
*head为当前结点,pre为当前结点的前一结点,next为当前结点的下一结点。
*pre结点可以反转指向,但反转之后如果不用next结点保存next结点的话,链表就断开了
*循环:
先用next保存下一个结点的信息,保证单链表不会因为失去head结点的原next结点而就此断裂;
保存完next,可以让head从指向next变成指向pre
head指向pre后,就继续依次反转下一个结点
让pre、head、next依次向后移动一个结点,继续下一次的指针反转。
*如果head为null的时候,pre就为最后一个结点,但是链表已经反转完毕,pre就是反转后链表的第一个结点。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if (head==null) return null;
ListNode pre=null;//初始化对象
ListNode next=null;
while(head!=null){
next=head.next;//保存head.next
head.next=pre;//改变.next指向,反转
pre=head;//后移
head=next;
}
return pre;
}
}
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
if pHead==None:
return None
pre=None//直接定义;nextnode使用时再定义;
while(pHead):
nextnode=pHead.next
pHead.next=pre
pre=pHead
pHead=nextnode
return pre
合并两个排序的链表
递归:注意链表为空的情况;
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
if pHead1==None:
return pHead2
if pHead2==None:
return pHead1
if pHead1.val<pHead2.val:
res=pHead1
res.next=self.Merge(pHead1.next,pHead2)
else:
res=pHead2
res.next=self.Merge(pHead1,pHead2.next)
return res
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null) return list2;
if(list2==null) return list1;
ListNode res=null;//先初始化一个res
if(list1.val<list2.val){
res=list1;
res.next=Merge(list1.next,list2);
}
else{
res=list2;
res.next=Merge(list1,list2.next);
}
return res;
}
}
删除链表中重复的结点
不包含重复的点
包含重复的点
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplication(self, pHead):
# write code here
first=ListNode(-1) #创建头节点
first.next=pHead
pre=first #前一个节点指向头节点
current=pHead
while current!=None:
duplicate=False
while current.next!=None and current.val==current.next.val:
current=current.next
duplicate=True
if duplicate==True:
pre.next=current.next
else:
pre=current
current=current.next
return first.next #相当于新的head
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
ListNode first=new ListNode(-1);
first.next=pHead;
ListNode pre=first;//指向当前确定不重复的节点
ListNode cur=pHead;//当前节点,遍历
while(cur!=null){
boolean duplicate=false;
while(cur.next!=null && cur.val==cur.next.val){
cur=cur.next;
duplicate=true;
}
if (duplicate==true) pre.next=cur.next;
else pre=cur;
cur=cur.next;
}
return first.next;
题型2:删除重复节点,留一个
pre 和current,
循环条件:current不为空 pre=current,current=current.next
当current.next!=None pre.val==current.val:
删除current :pre.next=current.next,current后移
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplication(self, pHead):
current=pHead
pre=None
while current!=None:
while current.next!=None and pre.val==current.val:#当前值与前一个相等,删除当前
pre.next=current.next
current=current.next
pre=current
current=current.next
return pHead