链表

一、快慢指针

与环有关、倒数第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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值