格式:
题号+题名+简单思路+code
※T141: 环形链表
- 快慢指针;只要进入环中,就一定会相遇
- 类似问题,T876: 链表的中间节点 (链表归并排序)
func hasCycle(head *ListNode) bool {
fast:=head
slow:=head
for fast!=nil && fast.Next!=nil {
fast=fast.Next.Next
slow=slow.Next
if fast==slow {
return true
}
}
return false
}
- 哈希法
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func hasCycle(head *ListNode) bool {
memo:=map[*ListNode]struct{}{}
curr:=head
for curr!=nil {
if _,ok:=memo[curr];ok {
return true
}
memo[curr]=struct{}{}
curr=curr.Next
}
return false
}
※T142: 环形链表Ⅱ
- 快慢指针
- 思路
首先假设头结点到环入口的距离为L,环的长度为C,而且L<=C,那么:
-
当慢指针到达环入口时,快指针比它多走L,即快指针需再多走C-L才能相遇;
-
由于v(快)-v(慢)=1且v(慢)=1,故相遇时慢指针又走了C-L,此时它与环起点距离为C-(C-L)=L;
至于L>C的情况,其实可先将L不断减去C直到L<=C ,就相当于快指针先在环内多跑了几圈,并不影响结果
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast=head
slow=head
while fast!=None and fast.next!=None:
fast=fast.next.next
slow=slow.next
if fast==slow:
break
if fast==None or fast.next==None:
return None
slow=head
while fast!=slow:
fast=fast.next
slow=slow.next
return fast
T206: 反转链表
- 迭代法;利用栈
# 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:
stack=[]
ans=ListNode(0)
tmp=ans
curr=head
while curr!=None:
stack.append(curr)
curr=curr.next
while len(stack)>0:
tmp.next=stack.pop()
tmp=tmp.next
tmp.next=None
return ans.next
- 迭代法;利用双指针(√)
# 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;curr=head
while curr!=None:
nxt=curr.next
curr.next=pre
pre=curr
curr=nxt
return pre
- 递归法;返回反转子链表的头节点(√)
# 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:
if head==None or head.next==None:
return head
tmp=self.reverseList(head.next)
head.next.next=head
head.next=None
return tmp
- 递归法;返回反转子链表的尾节点
# 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:
self.ans=ListNode(0)
self.reverseListAssist(head)
return self.ans.next
def reverseListAssist(self, head: ListNode) -> ListNode:
if head==None:
return self.ans
tmp=self.reverseListAssist(head.next)
tmp.next=head
head.next=None
return head
T92: 反转链表Ⅱ
- 利用栈,分为[0,m-1)+[m-1,n-1]+[n,N)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
ans=ListNode(0)
curr=ans
tmp=head
for i in range(m-1):
curr.next=tmp
curr=curr.next
tmp=tmp.next
stack=[]
for i in range(m,n+1):
stack.append(tmp)
tmp=tmp.next
for i in range(m,n+1):
tmp_s=stack.pop()
curr.next=tmp_s
curr=curr.next
tmp_s.next=None
while tmp!=None:
curr.next=tmp
tmp=tmp.next
curr=curr.next
return ans.next
- 递归
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
if m==1:
self.successor=None
return self.reverseN(head, n)
head.next=self.reverseBetween(head.next, m-1, n-1)
return head
def reverseN(self, head: ListNode, n: int) -> ListNode:
if n==1:
self.successor=head.next
return head
tmp=self.reverseN(head.next, n-1)
head.next.next=head
head.next=self.successor
return tmp
T148: 排序链表
- 要求O(NlogN)时间复杂度和O(1)空间复杂度
- 这里我主要的思路是类似数组归并排序方式,二分使用快慢指针找中点,合并时辅助数组用一个虚拟头节点即可
- 递归栈占用空间为O(logN),如果要达到O(1),应使用一个自底向上的方式通过迭代实现二分,参考题解
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
self.fakeHead=ListNode(-1)
return self.mergeSort(head)
def mergeSort(self, head: ListNode) -> ListNode:
if head==None or head.next==None:
return head
point1=head
point2=head.next
while point2!=None and point2.next!=None:
point2=point2.next.next
point1=point1.next
tmp=point1.next
point1.next=None
node1=self.mergeSort(head)
node2=self.mergeSort(tmp)
curr=self.fakeHead
while node1!=None or node2!=None:
if node1==None:
curr.next=node2
node2=node2.next
elif node2==None:
curr.next=node1
node1=node1.next
elif node1.val<=node2.val:
curr.next=node1
node1=node1.next
else:
curr.next=node2
node2=node2.next
curr=curr.next
tmp=self.fakeHead.next
self.fakeHead.next=None
return tmp
T143: 重排链表
- 使用双端队列
- O(N)时间复杂度,O(N)空间复杂度,存指针
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reorderList(head *ListNode) {
if head==nil {
return
}
deque:=[]*ListNode{}
curr:=head
for curr!=nil {
deque=append(deque, curr)
curr=curr.Next
}
ans:=&ListNode{-1,nil}
curr=ans
for len(deque)>0 {
curr.Next=deque[0]
deque=deque[1:]
curr=curr.Next
curr.Next=nil
if len(deque)>0 {
curr.Next=deque[len(deque)-1]
deque=deque[:len(deque)-1]
curr=curr.Next
curr.Next=nil
}
}
ans=nil
}
T109: 有序链表转换二叉搜索树
- 快慢指针找中点
- T108
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func sortedListToBST(head *ListNode) *TreeNode {
if head==nil {
return nil
}
if head.Next==nil {
return &TreeNode{head.Val, nil, nil}
}
curr:=head.Next.Next
tmp:=head
for curr!=nil && curr.Next!=nil {
curr=curr.Next.Next // 快指针起始位置
tmp=tmp.Next
}
node:=tmp.Next
tmp.Next=nil
head2:=node.Next
node_t:=&TreeNode{node.Val, sortedListToBST(head), sortedListToBST(head2)}
return node_t
}
T203: 移除链表元素
- 注意递归函数的意义: 返回删除给定元素的头节点
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeElements(head *ListNode, val int) *ListNode {
if head==nil {
return nil
}
if head.Val==val {
return removeElements(head.Next, val)
}
head.Next=removeElements(head.Next, val)
return head
}
T19: 删除倒数第n个节点
- 快慢双指针
- 注意头节点的删除
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeNthFromEnd(head *ListNode, n int) *ListNode {
point1:=head
point2:=head
for i:=0;i<n;i++ {
point1=point1.Next
}
if point1==nil {
return head.Next
}
for point1.Next!=nil {
point1=point1.Next
point2=point2.Next
}
point2.Next=point2.Next.Next
return head
}
T23: 合并k个排序链表
- 利用堆;O(Nlogk)时间复杂度
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
import "container/heap"
type PQ []*ListNode
func (p PQ) Len() int {
return len(p)
}
func (p PQ) Less(i int,j int) bool {
return p[i].Val-p[j].Val<0
}
func (p PQ) Swap(i int,j int) {
p[i],p[j]=p[j],p[i]
}
func (p *PQ) Push(x interface{}) {
*p=append(*p,x.(*ListNode))
}
func (p *PQ) Pop() interface{} {
x:=(*p)[len(*p)-1]
*p=(*p)[:len(*p)-1]
return x
}
func mergeKLists(lists []*ListNode) *ListNode {
pq:=&PQ{}
heap.Init(pq)
head:=&ListNode{0,nil}
curr:=head
for i:=0;i<len(lists);i++ {
if lists[i]!=nil {
heap.Push(pq,lists[i])
}
}
for pq.Len()>0 {
x:=heap.Pop(pq).(*ListNode)
if x.Next!=nil {
heap.Push(pq,x.Next)
}
x.Next=nil
curr.Next=x
curr=curr.Next
}
return head.Next
}
- 利用归并排序;O(Nlogk)时间复杂度
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeKLists(lists []*ListNode) *ListNode {
if len(lists)==0 {
return nil
}
return mergeAssist(lists,0,len(lists)-1)
}
func mergeAssist(lists []*ListNode,lo int,hi int) *ListNode {
if lo==hi {
return lists[lo]
}
mid:=(hi-lo)/2+lo
list1:=mergeAssist(lists,lo,mid)
list2:=mergeAssist(lists,mid+1,hi)
m_list:=merge2Lists(list1,list2)
return m_list
}
func merge2Lists(list1 *ListNode,list2 *ListNode) *ListNode {
head:=new(ListNode)
curr:=head
point1:=list1
point2:=list2
for point1!=nil || point2!=nil {
if point1==nil {
curr.Next=point2
point2=point2.Next
} else if point2==nil {
curr.Next=point1
point1=point1.Next
} else if point1.Val<point2.Val {
curr.Next=point1
point1=point1.Next
} else {
curr.Next=point2
point2=point2.Next
}
curr=curr.Next
curr.Next=nil
}
return head.Next
}
T328: 奇偶链表
- 分成奇数堆和偶数堆,然后将偶数堆接到奇数堆的末尾
- O(N)时间复杂度,O(1)空间复杂度
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func oddEvenList(head *ListNode) *ListNode {
if head==nil {
return nil
}
ix:=head
ans1:=new(ListNode)
curr1:=ans1
ans2:=new(ListNode)
curr2:=ans2
for ix!=nil {
curr1.Next=ix
curr1=curr1.Next
ix=ix.Next
curr1.Next=nil
if ix!=nil {
curr2.Next=ix
curr2=curr2.Next
ix=ix.Next
curr2.Next=nil
}
}
curr1.Next=ans2.Next
return ans1.Next
}
T2: 两数相加
- 逐个相加,注意进一
- O(N1+N2)时间复杂度
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
if l1==nil && l2==nil {
return nil
}
t1:=l1
t2:=l2
ans:=&ListNode{}
head:=ans
flag:=0
for t1!=nil || t2!=nil {
v1:=0
v2:=0
if t1!=nil {
v1=t1.Val
t1=t1.Next
}
if t2!=nil {
v2=t2.Val
t2=t2.Next
}
v:=v1+v2+flag
if v>=10 {
flag=1
v=v-10
} else {
flag=0
}
ans.Next=&ListNode{v,nil}
ans=ans.Next
}
if flag==1 {
ans.Next=&ListNode{1,nil}
}
return head.Next
}
T445: 两数相加Ⅱ
- 变种,使用stack逆序输出
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
type Stack []*ListNode
func (s *Stack) Push(i *ListNode) {
*s=append(*s,i)
}
func (s *Stack) Pop() *ListNode {
x:=(*s)[len(*s)-1]
*s=(*s)[:len(*s)-1]
return x
}
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
s1:=Stack{}
s2:=Stack{}
curr1:=l1
curr2:=l2
for curr1!=nil {
s1.Push(curr1)
curr1=curr1.Next
}
for curr2!=nil {
s2.Push(curr2)
curr2=curr2.Next
}
flag:=0
head:=Stack{}
for len(s1)>0 || len(s2)>0 {
v1:=0
v2:=0
if len(s1)>0 {
v1=s1.Pop().Val
}
if len(s2)>0 {
v2=s2.Pop().Val
}
v:=v1+v2+flag
flag=v/10
v=v%10
head.Push(&ListNode{v,nil})
}
if flag==1 {
head.Push(&ListNode{1,nil})
}
ans:=new(ListNode)
curr:=ans
for len(head)>0 {
curr.Next=head.Pop()
curr=curr.Next
}
return ans.Next
}
T160: 两个链表的第一个公共节点
- 类似两数相加的哈希表法,边遍历边存值;O(N1+N2)/字典开销
- 快慢双指针
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
currA:=headA
currB:=headB
lenA:=0
lenB:=0
for currA!=nil || currB!=nil {
if currA!=nil {
lenA++
currA=currA.Next
}
if currB!=nil {
lenB++
currB=currB.Next
}
}
currA=headA
currB=headB
if lenA<lenB {
diff:=lenB-lenA
for i:=0;i<diff;i++ {
currB=currB.Next
}
for currA!=nil {
if currA==currB {
return currA
}
currA=currA.Next
currB=currB.Next
}
} else {
diff:=lenA-lenB
for i:=0;i<diff;i++ {
currA=currA.Next
}
for currB!=nil {
if currA==currB {
return currB
}
currA=currA.Next
currB=currB.Next
}
}
return nil
}
- a+x+b=b+x+a
- a+b=b+a
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
node1=headA
node2=headB
while node1!=node2:
node1=node1.next if node1 else headB
node2=node2.next if node2 else headA
return node1
T24: 两两交换链表节点
- 练习递归
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func swapPairs(node *ListNode) *ListNode {
if node==nil || node.Next==nil {
return node
}
tmp:=node.Next
node.Next=swapPairs(tmp.Next)
tmp.Next=node
return tmp
}
T25: K个一组翻转链表
- 分为两步:
1 如何翻转长度为K的链表
2 递归对剩下的n-K个链表进行K个一组翻转 - 使用栈翻转长度为K的链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
type Stack []*ListNode
func (s *Stack) Push(i *ListNode) {
*s=append(*s,i)
}
func (s *Stack) Pop() *ListNode {
x:=(*s)[len(*s)-1]
*s=(*s)[:len(*s)-1]
return x
}
func reverseKGroup(head *ListNode, k int) *ListNode {
head,tail,n:=reverseAssist(head,k)
if n<k {
return head
}
tail.Next=reverseKGroup(tail.Next,k)
return head
}
func reverseAssist(head *ListNode, k int) (*ListNode,*ListNode,int) {
n:=0
curr:=head
s:=Stack{}
for curr!=nil && n<k{
s.Push(curr)
curr=curr.Next
n++
}
if n<k {
return head,nil,n
}
ans:=s.Pop()
curr_a:=ans
for len(s)>0 {
curr_a.Next=s.Pop()
curr_a=curr_a.Next
}
head.Next=curr
return ans,head,k
}
- 使用双指针翻转长度为K的链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseKGroup(head *ListNode, k int) *ListNode {
nodeA:=head
nodeB:=head
n:=0
for nodeB!=nil && n<k {
nodeB=nodeB.Next
n++
}
if n<k {
return head
}
tmp:=reverseAB(nodeA,nodeB)
nodeA.Next=reverseKGroup(nodeB, k)
return tmp
}
func reverseAB(nodeA *ListNode, nodeB *ListNode) *ListNode {
var pre *ListNode=nil
curr:=nodeA
for curr!=nodeB {
nxt:=curr.Next
curr.Next=pre
pre=curr
curr=nxt
}
return pre
}
T263: 丑数
func isUgly(num int) bool {
if num==0 {
return false
}
if num==1 || num==2 || num==3 || num==5 {
return true
}
if num%2==0 && num%3==0 && num%5==0 {
return isUgly(num/2) || isUgly(num/3) || isUgly(num/5)
} else if num%2!=0 && num%3==0 && num%5==0 {
return isUgly(num/3) || isUgly(num/5)
} else if num%2==0 && num%3!=0 && num%5==0 {
return isUgly(num/2) || isUgly(num/5)
} else if num%2==0 && num%3==0 && num%5!=0 {
return isUgly(num/2) || isUgly(num/3)
} else if num%2!=0 && num%3!=0 && num%5==0 {
return isUgly(num/5)
} else if num%2!=0 && num%3==0 && num%5!=0 {
return isUgly(num/3)
} else if num%2==0 && num%3!=0 && num%5!=0 {
return isUgly(num/2)
} else {
return false
}
T82: 删除排序链表中的重复元素Ⅱ
- 排序+快慢双指针
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode ans = new ListNode(-1);
ListNode fast = head, slow = head, curr = ans;
while (fast != null) {
int count = 0;
while (fast != null && fast.val == slow.val) {
count++;
fast = fast.next;
}
if (count == 1) {
curr.next = slow;
curr = curr.next;
}
slow = fast;
}
curr.next = null;
return ans.next;
}
}