leetcode-链表

翻转链表的题主要是找到翻转之后接到原链表上的节点

链表翻转

206 反转链表

反转链表可以不用一个dummy节点,而是返回pre。因为反转链表之后,箭头的顺序变了。1-2-3,1-2-3这样箭头反过来。

力扣

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None
        cur = head
        while cur:
            temp = cur.next   # 先把原来cur.next位置存起来
            cur.next = pre
            pre = cur
            cur = temp
        return pre

作者:han-han-a-gou
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/tu-jie-liu-cheng-python3die-dai-xiang-jie-by-han-h/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

234 回文链表

翻转链表法,o(1)空间复杂度。快慢指针找链表中点。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def isPalindrome(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        #快慢指针找中点,慢指针一边走一边翻转
        #找到中点后,遍历左右两边(左边是pre,右边是slow)
        pre=None
        slow=head
        fast=head
        while fast and fast.next:
            fast=fast.next.next
            # slow=slow.next
            #翻转链表
            tmp=slow.next
            slow.next=pre
            pre=slow
            slow=tmp
            #pre等于slow,slow等于slow.next,最后是slow在pre后面一位
        #如果是奇数的话,跳过中间的那个数
        if fast:
            slow=slow.next
        while slow and slow.val==pre.val:
            slow=slow.next
            pre=pre.next
        if pre is None:
            return True
        return False
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def isPalindrome(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        #快慢指针找中点,翻转后半段,1->2->3->4->5->6->7,1->2->3,4<-5<-6
        #比较前半段和后半段
        #再把后半段翻转过来,接上(可不做)
        slow = head
        fast = head
        if not fast.next:
            return True
        while fast and fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
        #奇数的时候,slow是中点,偶数的时候,slow是前半段最后一个
        #slow.next就是后半段的起点
        def reverse(cur_head):
            #从head开始翻转
            pre = None 
            cur = cur_head 
            while cur:
                nexts = cur.next
                cur.next = pre 
                pre = cur 
                cur = nexts
            return pre 
        reversed_tail = reverse(slow.next)
        #比较前半段和后半段
        cur1 = reversed_tail
        cur2 = head
        while cur1:
            tail_val = cur1.val 
            head_val = cur2.val 
            if tail_val != head_val:
                return False
            cur1 = cur1.next
            cur2 = cur2.next
        return True

24 两两交换链表中的节点

力扣

力扣

 思考:为什么要用三个指针,temp,node1,node2,用node1和node2好理解,要交换这两个,那么为什么再用个temp呢?因为交换的时候要把后面的节点和前面的节点相连,不用temp的话找不到前面那个节点。这个思想在lru里也有,lru为什么要用双链表,因为要找前一个和后一个。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        #用三个指针,pre,first,second来交换,pre是两个一组,前面的节点连接的那个
        dummy = ListNode(0)
        dummy.next = head
        pre = dummy
        while pre.next and pre.next.next:
            first = pre.next
            second = pre.next.next
            #交换
            first.next = second.next #第一个节点连接到第二个节点后面的一个节点
            second.next = first #第二个节点连接到第一个节点
            pre.next = second #前一个节点连接到第二个节点(本来是连接到第一个节点的)
            pre = first
        return dummy.next

25 k个一组翻转链表

分为三个步骤,1是找到k 个链表,2是翻转这k个链表,3是把链表前后相连。

和 lru差不多,lru也是先拆掉,然后再接上。

reverse的时候用pre指针去判断,直接翻转链表是用cur指针

reverse和直接翻转链表是一样的其实。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverse(self,head,tail):
        pre = None
        cur = head
        #为什么这里不能用while cur?
        #因为这段链表在长链表上没有断开
        while pre!=tail:
            temp = cur.next   # 先把原来cur.next位置存起来
            cur.next = pre
            pre = cur
            cur = temp
        return tail,head
    def reverseKGroup(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        #pre指针和前面连接,next指针和后面连接
        hair = ListNode(0)
        hair.next = head
        pre = hair
        while head:
            tail = pre
            for i in range(k):
                tail=tail.next
                if not tail:
                    return hair.next
            nex=tail.next
            head, tail = self.reverse(head, tail)
            # 把子链表重新接回原链表
            pre.next = head
            tail.next = nex
            pre = tail
            head = tail.next
        return hair.next


        

复杂链表的复制

复制2遍:行不通

138. 复制带随机指针的链表 看题解挺复杂,我的理解是:遍历2次,第一次复制原节点,第二次再复制随机节点。这么想哪里有bug吗

知道了。。不加任何技巧去复制随机指针,复制不到

"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        #遍历2次,第一次复制原节点,第二次再复制随机节点。
        newdummy=Node(0)
        newhead=Node(head.val)
        newdummy.next=newhead
        dummy=Node(0)
        dummy.next=head
        while head.next:
            newheadnext=Node(head.next.val)
            head=head.next
            newhead.next=newheadnext
            newhead=newhead.next
        head=dummy.next
        newhead=newdummy.next
        while head.next:
            headrandom=head.random.val 

原地复制

[剑指offer] 复杂链表的复制 - Python_jiangjiane的博客-CSDN博客

"""
# Definition for a Node.
class Node:
    def __init__(self, x, next=None, random=None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: Node
        :rtype: Node
        """
        if not head:
            return None
        #分为三步,先复制主节点,再复制随机节点,最后断开。
        #复制主节点
        cur=head
        while cur:
            copynode=Node(cur.val)
            curnext=cur.next
            cur.next=copynode
            copynode.next=curnext
            cur=curnext
        #连接副节点
        cur=head
        while cur:
            currandom=cur.random
            curnext=cur.next
            if currandom:
                curnext.random=currandom.next
            cur=curnext.next
        #拆开
        cur=head
        copyhead=head.next
        while cur:
            copynode=cur.next
            curnext=copynode.next
            cur.next=curnext
            if curnext:
                copynode.next=curnext.next
            cur=curnext
        return copyhead



哈希表存储

哈希法比较方便

力扣

"""
# Definition for a Node.
class Node:
    def __init__(self, x, next=None, random=None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: Node
        :rtype: Node
        """
                #异常值
        if not head:
            return None
        #创建一个哈希表
        keyvalue={}
        old=head
        while old:
            #将节点加入到字典里
            if old not in keyvalue:
                keyvalue[old]=Node(old.val)
            # 建立新节点之间的连接关系
            if old.next:
                if old.next not in keyvalue:
                    keyvalue[old.next]=Node(old.next.val)
                keyvalue[old].next=keyvalue[old.next]
            if old.random:
                if old.random not in keyvalue:
                    keyvalue[old.random] = Node(old.random.val)
                keyvalue[old].random = keyvalue[old.random]
            old = old.next
        return keyvalue[head]

链表排序

5.合并两个有序链表

6.排序链表

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def sortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head is None or head.next is None:
            return head
        #左边
        left=head
        #终点
        mid=self.getmid(head)
        #右边
        right=mid.next
        mid.next=None
        #递归
        return self.merge(self.sortList(left),self.sortList(right))
    
    def merge(self,left,right):
        dummy=ListNode(0)
        tmp=dummy
        while left and right:
            if left.val<right.val:
                tmp.next=left
                left=left.next
            else:
                tmp.next=right
                right=right.next
            tmp=tmp.next
        if left:
            tmp.next=left
        if right:
            tmp.next=right
        return dummy.next
    #快慢指针找中点
    def getmid(self,node):
        if node is None:
            return None
        fast=slow=node
        while fast.next and fast.next.next:
            fast,slow=fast.next.next,slow.next
        return slow

力扣

迭代归并

/**
 * 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 sortList(ListNode head) {
        int length = getLength(head);
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
       
        for(int step = 1; step < length; step*=2){ //依次将链表分成1块,2块,4块...
            //每次变换步长,pre指针和cur指针都初始化在链表头
            ListNode pre = dummy; 
            ListNode cur = dummy.next;
            while(cur!=null){
                ListNode h1 = cur; //第一部分头 (第二次循环之后,cur为剩余部分头,不断往后把链表按照步长step分成一块一块...)
                ListNode h2 = split(h1,step);  //第二部分头
                cur = split(h2,step); //剩余部分的头
                ListNode temp = merge(h1,h2); //将一二部分排序合并
                pre.next = temp; //将前面的部分与排序好的部分连接
                while(pre.next!=null){
                    pre = pre.next; //把pre指针移动到排序好的部分的末尾
                }
            }
        }
        return dummy.next;
    }
    public int getLength(ListNode head){
    //获取链表长度
        int count = 0;
        while(head!=null){
            count++;
            head=head.next;
        }
        return count;
    }
    public ListNode split(ListNode head,int step){
        //断链操作 返回第二部分链表头
        if(head==null)  return null;
        ListNode cur = head;
        for(int i=1; i<step && cur.next!=null; i++){
            cur = cur.next;
        }
        ListNode right = cur.next;
        cur.next = null; //切断连接
        return right;
    }
    public ListNode merge(ListNode h1, ListNode h2){
    //合并两个有序链表
        ListNode head = new ListNode(-1);
        ListNode p = head;
        while(h1!=null && h2!=null){
            if(h1.val < h2.val){
                p.next = h1;
                h1 = h1.next;
            }
            else{
                p.next = h2;
                h2 = h2.next;
            }
            p = p.next;           
        }
        if(h1!=null)    p.next = h1;
        if(h2!=null)    p.next = h2;

        return head.next;     
    }
}

作者:cherry-n1
链接:https://leetcode.cn/problems/sort-list/solution/pai-xu-lian-biao-di-gui-die-dai-xiang-jie-by-cherr/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

23 合并k个升序链表

力扣

class Solution(object):
	def mergeKLists(self, lists):	
		if not lists:
			return None
		# 通过mid将数组一分为二,并不断缩小规模,当规模为1时返回并开始合并
		# 通过合并两个链表,不断增大其规模,整体看就是不断缩小-最后不断扩大的过程
		def helper(begin,end):
			if begin==end:
				return lists[begin]
			mid = begin+(end-begin)/2
			left = helper(begin,mid)
			right = helper(mid+1,end)
			return merge(left,right)
		# 合并两个有序链表	
		def merge(a,b):
			if not (a and b):
				return a if a else b
			if a.val<=b.val:
				a.next = merge(a.next,b)
				return a
			else:
				b.next = merge(a,b.next)
				return b
		return helper(0,len(lists)-1)

其他

两个链表的第一个公共节点

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值