LeetCode | C++ 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II

52 篇文章 0 订阅

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

24题目链接

  • 为啥最开始需要将current节点指向虚拟头结点,是因为想要交换节点1和节点2的值,虚拟头结点、节点1和节点2的指向都需要发生改变。
  • 需要注意的是,当改变一个节点的next值后,原先的链接就没了。所以当需要改变一个节点的next值后,需要先将该节点指向的节点先用临时变量存储下来。
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* virtualHead = new ListNode(0);
        virtualHead->next = head;
        ListNode* current = new ListNode(0);
        current = virtualHead;
        while(current->next != NULL && current->next->next != NULL) {
            ListNode* tmp1 = current->next;
            ListNode* tmp2 = current->next->next->next;
            current->next = current->next->next;
            current->next->next = tmp1;
            current->next->next->next = tmp2;
            current = current->next->next;
        }
        return virtualHead->next;
    }
};

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

19题目链接

  • 暴力解法:先计算链表的长度,然后转换成正着数 第(总数 - N)个节点。
  • 快慢指针法:让快节点先走 n 步, 然后快慢节点一块走,直到快节点走到末尾,那么慢节点即为所需要删除的节点。
  • 因为要删除某个节点,需要获取它的上一个节点,所以需要让慢节点少走一步,即等价于快节点多走一步。

暴力解法

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 暴力解法
        ListNode* virtualHead = new ListNode(0);
        virtualHead->next = head;
        ListNode* current = virtualHead;
        int count = 0;
        while(current->next != NULL) {
            current = current->next;
            count++;
        }
        current = virtualHead;
        while((count - n) != 0) {
            current = current->next;
            count--;
        }
        ListNode* tmp = current->next;
        current->next = current->next->next;
        delete tmp;
        return virtualHead->next;
    }
};

快慢指针法

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 快慢指针法
        // 让快节点先走 n 步, 然后快慢节点一块走,
        // 直到快节点走到末尾,那么慢节点即为所需要删除的节点
        ListNode* virtualHead = new ListNode(0);
        virtualHead->next = head;
        ListNode* fast = virtualHead;
        ListNode* slow = virtualHead;

        // 因为要删除某个节点,需要获取它的上一个节点,所以需要让慢节点少走一步,
        // 即等价于快节点多走一步
        n++; 
        // 在这里 fast != NULL 或者 fast->next != NULL 判断是否到达末尾的标志,
        // 两者都行,一个指向NULL,一个指向尾节点, 但是无论选择那个,都要保持一致,
        // 可以画个图梳理下,对于fast->next != NULL 就不需要n++了,
        // 因为两者同步移动的时候 较之第一个条件,会整体少走一步。
        while (n-- != 0 && fast != NULL) {  
            fast = fast->next;
        }
        while (fast != NULL) {
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* tmp = slow->next;
        slow->next = slow->next->next;
        delete tmp;
        return virtualHead->next;
    }
};

面试题 02.07. 链表相交

题目链接

  • 若两个链表相交,则从相交位置他们的后面的长度一定相等,所以需要先将两者的长度对齐,两个链表相当于是右对齐,即让长的链表先走,直到和短列表长度相等,然后在逐个节点去判断。
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* currentA = headA;
        ListNode* currentB = headB;

        int lengthA = 0;
        int lengthB = 0;
        while (currentA != NULL) {
            currentA = currentA->next;
            lengthA++;
        }
        while (currentB != NULL) {
            currentB = currentB->next;
            lengthB++;
        }

        currentA = headA;
        currentB = headB;

        int delta;
        if (lengthA > lengthB) {
            delta = lengthA - lengthB;
            while (delta-- != 0) {
                currentA = currentA->next;
            }
        } else if (lengthB > lengthA) {
            delta = lengthB - lengthA;
            while (delta-- != 0) {
                currentB = currentB->next;
            }
        } else;

        ListNode* interVal;
        while(currentA != NULL) {
            if (currentA == currentB) {
                interVal = currentA;
                return interVal;
            }
            else {
                interVal = NULL;
            }
            currentA = currentA->next;
            currentB = currentB->next;
        }
        return interVal;
    }
};

142.环形链表II

142题目链接

  • 暴力解法:将遍历的节点每次移动一个,就需要跟前面除自己的所有节点进行比对,是否有相等的,有则为环。简单粗暴但是效率太低。
  • 快慢指针法:非常巧妙的运用了数学的知识,通过类似于速度路程关系,可以推出两者在圈内相遇后,从相遇点到入环处和从起点到入环处的距离是一样或者差(n - 1)* 环长,基于此等式,即可得出。
  • L1 = (n - 1) * (L2 + L3) + L3 (L1: 从起点到入环口的距离;L2:从入环口到相遇点的距离; L3:从相遇点再到入环口的距离) 当 n = 1时, L1 = L3; 当 n > 1 时, 相当于 快指针 在环里多转了(n - 1) 圈,在遇到 慢指针, 但是相遇点 仍是 入环口。

暴力解法

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 暴力解法
        ListNode* currentA = head;
        ListNode* currentB = head;
        int count = 0;
        while(currentB != NULL) {
            currentB = currentB->next;
            count++;
            int tmpCount = count - 1;
            // B每次移动一个,就需要跟前面除自己的所有节点进行比对,是否有相等的,有则为环。
            currentA = head;
            while (tmpCount-- != 0 && currentA != currentB) {
                currentA = currentA->next;
            }
            if (tmpCount > 0) {
                return currentA;
            }
        }
        return NULL;
    }
};

快慢指针法

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 快慢指针法
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != NULL && fast->next != NULL) {
            fast = fast->next->next;
            slow = slow->next;
            if (fast == slow) {
                ListNode* index1 = head;
                ListNode* index2 = fast;
                while (index1 != index2) {
                    index1 = index1->next;
                    index2 = index2->next;
                }
                return index1;
            }
        }
        return NULL;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值