手撕代码之链表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/daaikuaichuan/article/details/89155180

一、反转链表(leetcode 206)

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 用两个指针记录下当前指针的前驱和后继,然后不断更新指针的指向
        ListNode *pPre = nullptr, *pNext; 
        while (head != nullptr){
            // 保存当前结点的下一个结点,防止链表断裂找不到后继
            pNext = head->next;
            // 修改当前结点的指向
            head->next = pPre;
            // 更新指针
            pPre = head;
            head = pNext;
        }
        return pPre;
    }
};

二、两个链表的交点(leetcode 160)

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int len1 = 0, len2 = 0;
        ListNode *tmpA = headA;
        ListNode *tmpB = headB;
        // 先计算两个链表的长度
        while (tmpA != nullptr){
            len1++;
            tmpA = tmpA->next;
        }
        while (tmpB != nullptr){
            len2++;
            tmpB = tmpB->next;
        }
        if (len1 > len2){
            int tmp = len1 - len2;
            // 让长度较长的链表先走一段距离
            for (int i = 0; i < tmp; ++i)
                headA = headA->next;
            // 之后两个结点齐头并进,如果相遇则找到相交的结点了
            while (headA != nullptr && headB != nullptr){
                if (headA == headB)
                    return headA;
                headA = headA->next;
                headB = headB->next;
            }
        }
        else{
            int tmp = len2 - len1;
            for (int i = 0; i < tmp; ++i)
                headB = headB->next;
            while (headB != nullptr && headA != nullptr){
                if (headB == headA)
                    return headB;
                headA = headA->next;
                headB = headB->next;
            }
        }
        return nullptr;
    }
};

三、链表的中间结点(leetcode 876)

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode *pTmp = head;
        while (head != nullptr && head->next != nullptr){
            // 快慢指针,快指针每次走两步,慢指针每次走一步,当快指针到头了,
            // 那么慢指针就是中间结点
            pTmp = pTmp->next;
            head = head->next->next;
        }
        return pTmp;
    }
};

四、判断链表是否存在环(leetcode 141)

class Solution {
public:
    bool hasCycle(ListNode *head) {
        // 快慢指针
	    ListNode *pSlow = head, *pFast = head;
	    while (pSlow != nullptr && pFast != nullptr && pFast->next != nullptr)
	    {
	    	pSlow = pSlow->next;
	    	pFast = pFast->next->next;
            // 当快慢指针相遇时,即链表存在环
            if (pSlow == pFast)
	    		return true;
		}
		return false;
    }
};

五、输出链表环的入口结点(leetcode 142)

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *pSlow = head, *pFast = head;
        // 先使用快慢指针找到相遇的结点
        while (pFast != nullptr && pFast->next != nullptr){
            pSlow = pSlow->next;
            pFast = pFast->next->next;
            if (pSlow == pFast)
                break;
        }
        if (pFast == nullptr || pFast->next == nullptr)
            return nullptr;
        // 将慢指针移动到头结点,然后快慢指针前进速度变为一样,之后再相遇则为入口结点
        pSlow = head;
        while (pSlow != pFast){
            pSlow = pSlow->next;
            pFast = pFast->next;            
        }
        return pSlow;
    }
};

六、删除链表中倒数第k个节点(leetcode 19)

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if (head == nullptr) return nullptr;
        ListNode *p1 = head, *p2 = head;
        // 使用双指针找到倒数第K个结点
        for (int i = 0; i < n; ++i){
            p2 = p2->next;
        }
        if (p2 == nullptr)
            return head->next;
        while (p2->next != nullptr){
            p1 = p1->next;
            p2 = p2->next;
        }
        // 删除第K个结点
        p1->next = p1->next->next;
        return head;
    }
};

七、合并两个排序链表(leetcode 21)

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *pHead;
        // 某一个链表为空则返回较长的那个
        if (l1 == nullptr) return l2;
        if (l2 == nullptr) return l1;
        if (l1->val <= l2->val){
            // 新链表的头结点是两个链表中较小的一个
            pHead = l1;
            // 新链表的下一个结点则是由原来较小的链表的下一个结点和原来较长的链表产生
            pHead->next = mergeTwoLists(l1->next, l2);
        }
        else{
            pHead = l2;
            pHead->next = mergeTwoLists(l1, l2->next);               
        }
        return pHead;
    }
};

八、O(1)时间删除链表中的一个结点(leetcode 237)

class Solution {
public:
    void deleteNode(ListNode* node) {
        // 保存当前结点的下一个结点
        ListNode *pTemp = node->next;
        // 把下一个结点复制给当前结点
        node->val = pTemp->val;
        node->next = pTemp->next;
        // 删除下一个结点
        delete pTemp;
        pTemp = nullptr;
    }
};

九、删除重复的结点(leetcode 83)

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == nullptr || head->next == nullptr) return head;
        // 双指针,记录下一个结点是否和当前结点,如果两个结点相等,则删除后面一个结点
        ListNode *p1 = head, *p2 = head->next;
        while (p2 != nullptr){
            if (p1->val == p2->val){
                p1->next = p2->next;
                p2 = p2->next;
            }else{
                p1 = p1->next;
                p2 = p2->next;
            }
        }
        return head;
    }
};

猜你喜欢

转载自blog.csdn.net/daaikuaichuan/article/details/89155180