翻转链表的题主要是找到翻转之后接到原链表上的节点
链表翻转
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)