Leetcode(2)——链表

格式:

题号+题名+简单思路+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,那么:

  1. 当慢指针到达环入口时,快指针比它多走L,即快指针需再多走C-L才能相遇;

  2. 由于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;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值