[代码随想录算法训练营Day 04 链表Part 2]

Day 04

链表 Part 02

5. 两两交换链表中的节点(力扣24)

  1. 题目描述:两两交换链表中的结点
  2. 思路:题目中说不改变结点的内容,只进行交换,意思就是只 对链表指针的指向进行修改。
  • 要用虚拟头结点,这样可以对所有节点一视同仁的操作。
  • 因为涉及到三个节点的指针改变指向,所以这里设计三个指针,one two three。然后,想象将箭头拔下来,再插到预想的位置(下面那个图,把线扯平就是调换后的顺序啦~)。顺序上,因为有了one two three三个指针,这三个节点我们都能随时找得到,但是three的下一个节点需要three.next来指示,因此需要先把two的箭头插到three.next节点上。其余两个箭头拔插的顺序随意。
  • 一轮拔插后,再移动one two three三个节点向后,可以使用while循环,也可以用递归的方法。
    在这里插入图片描述
  1. Python 语法细节
  • python 逻辑求值的短路规则:因为这需要判断one 的下一个节点,和下下个节点是否有值,但是当one.next为空时,使用one.next.next会报错。而短路规则可以实现如果one.next为空,逻辑短路,不再向下求值。while one.next and one.next.next

在这里插入图片描述

  • 写递归调用的时候,最后一行不能只写调用函数,要加return
  1. Python实现
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        ## 三个指针交换法
        # dummy_head = ListNode(next=head)
        # one = dummy_head
        # while one.next and one.next.next:
        #     two = one.next
        #     three = two.next
        #     two.next = three.next
        #     one.next = three
        #     three.next = two
        #     one = two
        # return dummy_head.next

        ## 递归法
        dummy_head = ListNode(next=head)
        one = dummy_head
        return self.swap(one,dummy_head)
    def swap(self,one,dummy_head):
        if not one.next or not one.next.next:
            return dummy_head.next
        
        two = one.next
        three = two.next
        two.next = three.next
        one.next = three
        three.next = two
        one = two
        return self.swap(one,dummy_head)
  1. C++语法细节
  • 在一个成员函数中定义的局部变量其他成员函数无法访问
  1. C++实现
class Solution {
private:
    
    ListNode* one = nullptr, *two = nullptr, *three = nullptr;
    ListNode* result = nullptr;
public:
    ListNode* swapPairs(ListNode* head) {
        // //三指针法
        // ListNode* dummy = new ListNode(0,head);
        // ListNode* one = dummy;
        // ListNode* two = nullptr;
        // ListNode* three = nullptr;

        // while (one->next and one->next->next){
        //     two = one->next;
        //     three = two->next;
        //     two->next = three->next;
        //     one->next = three;
        //     three->next = two;
        //     one = one->next->next;
        // }
        // return dummy->next;

        // // 递归法  
        ListNode* dummy = new ListNode(0,head);
        one = dummy;
        result = dummy;     
        return swap(one);  
    }
    ListNode* swap(ListNode* one){
        if(not one->next or not one->next->next){
            return result->next;
        }
        two = one->next;
        three = two->next;
        two->next = three->next;
        one->next = three;
        three->next = two;
        return swap(one->next->next);
                                                                                                         
    }
};

6. 删除链表的倒数第n个节点(力扣19)

  1. 题目描述:删除链表的倒数第N个节点
  2. 思路:先遍历得到链表长度,再遍历导待删除的结点的前一个,让他直接指向后一个的后一个。如果想实现一次遍历就实现,用快慢指针。快慢指针就像从dummy发车的两趟列车,让快车比慢车早n+1站出发,这样当快车到达终点的时候,慢车正好到达倒数第n站再向前一站。
  3. python语法细节
  4. Python实现
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(0,head)
        one = dummy
        two = dummy
        num = 0
        while num<n:
            num = num+1
            one = one.next
        while one.next :
            one = one.next
            two = two.next
        two.next = two.next.next
        return dummy.next
  1. C++语法细节
  • C++中while循环写法:while后面条件要写括号
  • -while (condition) { // 循环体 // 这里是代码块,会在条件为真时重复执行 }
  1. C++实现
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0,head);
        ListNode* one = dummy;
        ListNode* two = dummy;
        for(int i =0;i<n;i++){
            one = one->next;
        }
        while (one->next){
            one = one->next;
            two = two->next;
        }
        two->next = two->next->next;
        return dummy->next;

    }
};

7.两链表相交(力扣 面试题02.07.链表相交)

  1. 题目描述:两链表相交
  2. 思路:根据示例,如果两链表有相交的地方,一定是在两链表的尾部。而且此题,相交的点不仅仅是值相同,而且相交的是同一个节点(不能根据值来判断是否是同一个节点,而要判指针指向的是同一个节点)。
  3. python语法细节
  • 当错误信息提示,cura 类型为NoneType时,不仅要检查是否为空指针,而且要检查是否被正确的初始化
  • 在 Python 中,通常用 None 表示空值,而不是 null。所以在函数中返回空值时,应该使用 None
  • Python中交换两个变量的值,不需要加一个中间变量,可以使用解包的方法直接交换。
    在这里插入图片描述
  1. Python实现
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        lena = 0
        cur = headA
        while cur:
            lena += 1
            cur = cur.next
        lenb = 0
        cur = headB
        while cur:
            lenb += 1
            cur = cur.next
        # 让a 是长的那个,如果不是,使用元组解包交换二者的位置
        if lenb > lena:
            lena,lenb = lenb,lena
            headA,headB = headB,headA
        cura = headA
        curb = headB
        for i in range(lena-lenb):
            cura = cura.next
        while cura:
            if(cura==curb):

                return cura
            else:
                cura = cura.next
                curb = curb.next
        return None
  1. C++语法细节
  2. C++实现
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int lenA = getlength(headA) ,lenB = getlength(headB);
        if(lenB > lenA){
            int tmp = lenA;
            lenA = lenB;
            lenB = tmp;
            ListNode* temp=headA;
            headA = headB;
            headB = temp;
        }
        ListNode* curA = headA;
        for(int i=0;i<lenA-lenB;i++){
            curA = curA->next;
        }
        ListNode* curB = headB;
        while (curA){
            if(curA == curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;

        
    }
    int getlength(ListNode* cur){
        int length = 0;
        while(cur){
            length += 1;
            cur = cur->next;
        }
        return length;
    }
};

8. 环形链表2 (力扣142)

  1. 题目描述:环形链表2

  2. 思路:很难,人脑很难想到…当一条路不知道什么位置开始遇到鬼打墙,我们发射两个指针,快指针一次走两步,慢指针一次走一步,如果有环,他俩一定会相遇,如果相遇,那么从相遇那个点和起始点在发射两个一次一步的指针,相遇点就是环入口。推导如下图,插入详细解释
    在这里插入图片描述

  3. python语法细节
    写代码时候要考虑无环的情况

  4. Python实现

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        fast ,slow = head,head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
            if fast == slow:
                another = head
                while slow!=another:
                    slow = slow.next
                    another = another.next
                return another
        return None
  1. C++语法细节
  • 要先让快慢指针跑起来,再判断相遇时刻。不然就在头结点判断相遇了…
  1. C++实现
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast and fast->next){
            
            fast = fast->next->next;
            slow = slow->next;
            if(fast==slow){
                slow = head;
                cout<<fast->val<<endl;
                while (fast){
                    if(fast==slow){
                        return fast;
                    }
                    fast = fast->next;
                    slow = slow->next;
                }
            }
        }
        return nullptr;


    }
};
  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值