DAY4 Leetcode24两两交换链表中的节点+Leetcode19删除链表的倒数第N个节点+面试题02.07.链表相交+Leetcode142循环链表II

题目链接/文章讲解/视频讲解: 代码随想录

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

题目要求:两两交换链表的节点,交换的是地址而不是节点中的值。

用dummyhead,交换节点的next指向即可,注意用tmp和tmp1做临时存储,画图能够更好理解。注意,这里在交换之后,cur和1以及2和3之间的链接关系会断开,因此需要中间变量临时村塾1和3的地址。

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* swapPairs(ListNode* head) {
        ListNode* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* cur = dummyhead;
        while (cur->next!=nullptr && cur->next->next!=nullptr){
            ListNode* tmp = cur->next;
            ListNode* tmp1 = cur->next->next->next;
            cur->next = cur->next->next;
            cur->next->next = tmp;
            cur->next->next->next = tmp1;
            cur = cur->next->next; // cur移位两位,准备下一轮交换
        }
        return dummyhead->next;
    }
};

Python:

# 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
        """
        dummyhead = ListNode(next=head)
        cur = dummyhead
        while cur.next and cur.next.next:
            tmp = cur.next
            tmp1 = cur.next.next.next
            cur.next = cur.next.next
            cur.next.next = tmp
            cur.next.next.next = tmp1
            cur = cur.next.next
        return dummyhead.next

Python(递归写法):

# 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
        """
        if head is None or head.next is None:
            return head
        pre = head
        cur = head.next
        next = head.next.next

        cur.next = pre
        pre.next = self.swapPairs(next)

        return cur

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

题目要求:给出头节点,删除链表的倒数第n个节点,返回头节点。

我的想法:取到倒数第n+1个节点作为cur,然后把cur->next指向cur->next->next,最后处理被删除的节点。

实际上采用双指针的写法,让快指针先动n步然后让快慢指针一起移动直到快指针指向NULL,删除慢指针指向的节点。

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* dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode* slow = dummyhead;
        ListNode* fast = dummyhead;
        while (n-- && fast!=nullptr){
            fast = fast->next;
        }
        fast = fast->next;
        while(fast!=nullptr){
            slow = slow->next;
            fast = fast->next;
        }
        ListNode* tmp = slow->next;
        slow->next = tmp->next;
        delete tmp;
        return dummyhead->next;
    }
};

Python:

# 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 removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        dummyhead = ListNode(next=head)
        slow = dummyhead
        fast = dummyhead
        for i in range(n+1):
            fast = fast.next
        while fast:
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next
        return dummyhead.next

160. 链表相交

题目要求:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null。

双指针curA和curB分别指向headA和headB,求出两个链表的长度并求出差值。让两个链表末尾对其,开始寻找交点,直到curA==curB或者等于NULL返回0。似乎并不存在两个节点的地址相同但是后续节点不同的情况。

C++:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB = 0;
        while (curA!=nullptr){
            lenA++;
            curA = curA->next;
        }
        while (curB!=nullptr){
            lenB++;
            curB = curB->next;
        }
        curA = headA;
        curB = headB;
        if (lenB > lenA){
            swap(lenA, lenB);
            swap(curA, curB);
        }
        int gap = lenA - lenB;
        while(gap--){
            curA = curA->next;
        }
        while(curA!=nullptr){
            if(curA==curB){
                return curA;
            }
            curA = curA->next;
            curB = curB->next;
        }
        return nullptr;
    }
};

Python:

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        curA = headA
        curB = headB
        lenA = lenB = 0
        while(curA!=None):
            lenA+=1
            curA = curA.next
        while(curB!=None):
            lenB+=1
            curB = curB.next
        curA = headA
        curB = headB
        if lenB > lenA:
            lenA, lenB = lenB, lenA
            curA, curB = curB, curA
        gap = lenA - lenB
        while gap:
            gap-=1
            curA = curA.next
        while(curA != None):
            if (curA==curB):
                return curA
            curA = curA.next
            curB = curB.next
        return None

142. 循环链表II

题目要求:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如何判断链表中是否有环?答:定义快慢指针,fast指针一次走两步,slow指针一次走一步。如果链表中有环则相当于fast在追击slow。如果fast走两步刚好到达slow的位置则相遇,如果fast走两步刚好到达slow的下一个节点,则slow再走一步也会相遇。因此如果链表中有环,则slow和fast一定会相遇。

如何找到环的入口?

慢指针slow走过的步数:x+y(一次走一步,长度即步数)

快指针fast走过的步数:(x+y+n(y+z))/2 (一次走两格,步数是长度除以2)

二者走过的步数相等,因此x+y=(x+y+n(y+z))/2,x+y=n(y+z)

我们需要求出x,x=(n-1)(y+z)+z,当n=1时,x=z说明从头节点出发和从相遇节点出发,每次走一个节点,会在入口处相遇。如果n>1,那么也是一样二者依然会在入口处相遇,只不过从相遇节点出发的指针会多走n-1圈。

因此我们只需要让fast和slow指针相遇,再让index1指针和index2指针分别从head和相遇节点出发。当index1和index2相遇时,返回即可得到入口节点的位置。

C++:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast!=nullptr && fast->next!=nullptr){
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast){
                ListNode* index1 = fast;
                ListNode* index2 = head;
                while (index1 != index2){
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index2;
            }
        }
        return nullptr;
    }
};

Python:

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        fast = slow = head
        while(fast!=None and fast.next!=None):
            slow = slow.next
            fast = fast.next.next
            if(slow==fast):
                index1 = fast
                index2 = head
                while(index1!=index2):
                    index1 = index1.next
                    index2 = index2.next
                return index2
        return None

总结:链表到这里就结束了,了解链表是一种特殊的数据结构(struct),包括了值(val)和指向的下一个节点的地址(next)。

// Python
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None
# C++
struct ListNode {
     int val;
     ListNode *next;
     ListNode(int x) : val(x), next(NULL) {}
 };

注意如何判断循环链表,注意应用双指针的思路。注意链表的指向,在改变链表指向位置时,可能需要tmp来暂存地址。注意在链表前加一个虚拟dummyhead可以链表操作的效率,但是最后也要delete掉dummyhead。C++中的内存需要手动释放,Python中当一个地址不被其他变量引用时,就会自动释放。大概就是这么多,链表说难也难,说不难也不难,还是需要多加训练!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值