代码随想录算法训练营第四天 | 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、​ 面试题 02.07. 链表相交

文章介绍了在链表操作中使用虚拟节点简化处理头节点,以及双指针技巧在交换节点、删除倒数第N个节点和检测环形链表中的应用,强调了数学思维在解决这类问题中的重要性。
摘要由CSDN通过智能技术生成

24. 两两交换链表中的节点

第一想法:看到提示说使用虚拟节点----那么为什么使用虚拟节点?--模拟节点交换的过程,看来是需要三个元素的关系的, 第一个节点指向 第三个节点,第三个节点指向第二个节点,第二个节点指向第三个节点的下一个节点。可以单独处理头结点,为了统一处理过程可以使用虚拟节点,让第一个节点当作第一轮的第一个节点

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func swapPairs(head *ListNode) *ListNode {
    // 处理空链表和一个值的链表
    if head == nil || head.Next ==nil{
        return head
    }
    // 使用虚拟头结点方便一些
    dummyHead := &ListNode{
        Val: -99,
        Next: head,
    }
    // 虚拟头结点,cur第一个节点
    pre := dummyHead
    cur := dummyHead.Next

    for  cur.Next != nil{
        tmp := cur.Next.Next
        pre.Next = cur.Next
        cur.Next.Next = cur
        cur.Next = tmp
        
        pre = cur
        cur = cur.Next
        if cur == nil{
            break
        }
    }
    return dummyHead.Next

}

总结:使用虚拟节点;处理头结点的过程;循环结束的判断条件 

19.删除链表的倒数第N个节点

第一想法:反转链表-删除第n个节点,再反转链表

其他的方法,如果是正序遍历 如何找到倒数第N个节点?想不到

看了讲解:使用双指针,两者之间相差n 然后fast指针指向最后一个节点的时候,slow另外一个指针就指向了倒数第N个节点。

        写出了当两个指针初始指向头结点时,当删除第一个节点的时候会出错的代码,头结点不好处理,这时想到了虚拟节点。让两个指针初始指向虚拟节点。

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeNthFromEnd(head *ListNode, n int) *ListNode {
    if head == nil || head.Next==nil{
        return nil
    }
    // 删除第一个节点的时候不好处理,使用虚拟节点
    dummyHead := &ListNode{
        Next: head,
    }
    slow , fast := dummyHead,dummyHead

    for i:=1; i<= n;i++{
        fast = fast.Next
    }
    for fast.Next != nil{
        slow = slow.Next
        fast = fast.Next
    }
    // 这时slow指向的是倒数第n个节点的前一个节点
    slow.Next = slow.Next.Next
    return dummyHead.Next

}

今日收获:删除单项链表中的倒数第n个链表,双指针可以实现,并且使用虚拟节点处理头节点的问题。

面试题 02.07. 链表相交 

第一想法:第一感觉像是那种 双循环的暴力循环的题,

看了题解:需要从数学角度分析一下,因为相交及其之后的部分是相同的,所以如果两个链表相交其尾部一定有一段是共同的。

        相交的情况:首先让其尾部对弃,两个指针指向两个链表重合的索引位置,判断两个位置是否是指向同一个元素,如果不是就移动到下一个,直到判断出出来指向同一个位置。

        不相交的情况:任意一个链表为空的情况;指针走到最后一个元素也不是指向同一个位置 

        

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func getIntersectionNode(headA, headB *ListNode) *ListNode {
    
    // 先判断一下返回为nil的情况
    
    // 两者不相交的情况下也是返回nil
    nodeA := headA
    lenA := 0
    nodeB := headB
    lenB := 0
    for nodeA != nil{
        lenA++
        nodeA = nodeA.Next
    }
    for nodeB != nil{
        lenB++
        nodeB = nodeB.Next
    }


    // 指针初始位置
    var offset int
    var fast, slow *ListNode
    if lenA > lenB{
        fast = headA
        slow = headB
        offset = lenA-lenB
        // for i:=1; i<=offset; i++{
        //     fast = fast.Next
        // }  
    }else{
        fast = headB
        slow = headA
        offset = lenB -lenA
        
    }
    for i:=1; i<=offset; i++{
            fast = fast.Next
    }
    for  fast != slow{
        fast = fast.Next
        slow = slow.Next
    }
    return fast
}

 写后总结:如何让指针同时指向两个链表尾部对其后的初始位置,先计算出链表长度,两者的差值,让长度较长的链表的指针从头节点移动差值步,两个指针就对其了,然后进行循环判断两个指针是否指向同一个节点,灵感来自于 删除倒数第N个节点 中两个指针的操作 也是相差N个节点

最主要的还是数学思想,尾端对齐后开始遍历,节点相同的位置及其之后都是相同的

​​​​​​142. 环形链表 II

第一想法:遍历节点,判断该节点的下一个节点是否是指向了 前面的节点,返回指向的节点

可以用hash表存储已经遍历的节点,遍历到那个节点判断hash表中的是否存在;

如果发现某个节点指向了nil 说明这个链表没有环

但是这个方法肯定不是 空间复杂度为o(1)的方法

我会选择,slow遍历到一个节点,fast就继续遍历下面的节点 看他们是否指向他,如果遍历到最后都没有指向 就 slow下一个节点,fast接着便利--太暴力了 太不优雅了

看了题解之后:发现是一个数学题

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值