CMU硕士101-我与链表的故事

CMU硕士101-我与链表的故事

链表的基本操作

翻转一个链表

有迭代法和递归法,这两个都要画图,手撕。

在这里插入图片描述

递归法详解:

/*
思路:
两个都要画图
链表的题目还是要画图.
方法一:迭代法
1->2->3->nullptr 转换成 nullpter->1->2->3
在遍历链表时,将curr节点的next指向pre,所以要先保存next节点,然后跳到之前的next,之前的next指向之前的curr
1,保存next节点
2,curr->next指向pre
3,pre变成curr,curr变成next

方法二:递归法
*/
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr) {
            ListNode* next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
};

/*
    [先画图用1->2来理解,](https://blog.csdn.net/w605283073/article/details/86653745?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163251905716780357275848%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163251905716780357275848&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-86653745.pc_search_insert_js_new&utm_term=%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8%E9%80%92%E5%BD%92&spm=1018.2226.3001.4187)
*/
struct ListNode* reverseList(struct ListNode* head)
{
     if((head == NULL )||(head->next==NULL))
        return head;
 
     struct ListNode *new_Head = reverseList(head->next);
     head->next->next = head;
     head->next = NULL;
     
     return new_Head;
}

合并链表:两个有序链表,合并成一个有序链表

21合并链表:两个有序链表,合并成一个有序链表
这题的可贵之处在于它是后面很多题目的基础,手撕。

在这里插入图片描述

/**
 * 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* mergeTwoLists(ListNode* l1, ListNode* l2) {
    ListNode *ret = new  ListNode(0), *node = ret;
    // 非递归法
    while (l1 && l2) {
        if (l1->val <= l2->val) {
            node->next = l1;
            l1 = l1->next;
        } else {
            node->next = l2;
            l2 = l2->next;
        }
        node = node->next;
    }
    node->next = l1?l1:l2;
    return ret->next;
}
};

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

这题要学会怎样交换链表中的两个节点,画个图更清晰
在这里插入图片描述
参考链接:

class Solution {
public:
    void swapTwo(ListNode* start){
        ListNode* a=start->next;
        ListNode* b=start->next->next;
        start->next=b;
        a->next=b->next;
        b->next=a;
    }

    ListNode* swapPairs(ListNode* head) {
        ListNode* start=new ListNode(0);
        start->next=head;
        //哨兵节点 ans,用于记录链表的开头,方便输出
        ListNode* ans=start;
    
        while(start->next!=nullptr && start->next->next!=nullptr){
            swapTwo(start);
            //不能忘了更新 start
            start=start->next->next;
        }
        return ans->next;
    }

};

160 判断链表能否交于一点*

在这里插入图片描述

 /*
 思路:
 如果要返回相交点位置, 我们必须让两个head从距离末尾相等的地方遍历. 但两个链表的长度有可能是不同的,
 所以我们应该选取短链表的头节点位置,所以问题转换成 “如何消除两个链表的长度差?”
 solution:两个head同时从头部遍历,到达尾部的那个节点,指向另一个链表的头结点。这样就消除了链表差。
 如果链表相交,会交于一个非空点。如果不会相交,最后相聚的就是空节点。
 如果两个链表相交,相交之后的长度是相同的。
 */
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
  要参考:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/solution/tu-jie-xiang-jiao-lian-biao-by-user7208t/
错在, pA = (pA == nullptr) ? headB:pA->next;
如果pA走到了末尾,将pA指向另一个链表的头结点。
如果没有走到末尾,指向pA的next
 */

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if (headA == nullptr || headB == nullptr) { // 链表一般都要判空
            return nullptr;
        }
         ListNode *pA = headA, *pB = headB;
         while(pA != pB) {
             pA = (pA == nullptr) ? headB:pA->next;
             pB = (pB == nullptr) ? headA:pB->next;
         }
        return pA;
    }
};

234 判断链表是否回文

在这里插入图片描述

/*
一个链表是不是回文链表
方法一:将链表中的数据都提取到vector中,转换成vec,比较机械。不建议。
方法二:找到链中间的点,然后翻转后半段链表,让两段链表逐个比较
前半段和后半段逐个比较,要保存头节点和中间节点。
*/

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr) {
            ListNode* next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }

    bool isPalindrome(ListNode* head) {
 
        ListNode *pHead = head;
   
        ListNode *slow = head, *fast = head;
        // 找到中间节点
        while(fast->next && fast->next->next) { // 这里为什么找到 while(slow->next && fast->next->next) 就会判断空指针。因为对的要更严格一些。
            slow = slow->next;
            fast = fast->next->next;
        }
        // 保存中间节点,奇偶怎样考虑(画图ok)
        ListNode *mid = slow;
    
        // 翻转mid之后的链表
        ListNode *reverseAfterMid = reverseList(mid);

        // 判断前半段和后半段是否相等
        while(pHead && reverseAfterMid) {
    
            if(pHead->val != reverseAfterMid->val) {
                return false;
            }
            pHead = pHead->next;
            reverseAfterMid = reverseAfterMid->next;
        }
        return true;
    }
};

83 . 删除排序链表中的重复元素


在这里插入图片描述

 // 思路:按照升序排列, 保存头结点,遍历数组,next和当前相等的,next = next->next 
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == nullptr) { // 判空
            return head;
        }

        ListNode *pHead = head; // 保存头结点
        while(head && head->next) {
            if (head->next->val == head->val) { // 当下一个值与head val相同时,一直到让next等于next->next,遇到不相等的,让head指向下一个next
                head->next = head->next->next;
            } else { 
                head = head->next; // 这里纠结了一下,考虑{1,1,1}的场景
            }
        }
        return pHead;
    }
};

328. 奇偶链表


在这里插入图片描述

/*
思路:分开两条路一奇一偶,然后让奇数链表最后挂接偶数链表,最终返回奇数链表的头部
*/
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        // 判空
        if (head == nullptr || head->next == nullptr) { 
            return head;
        }
        // 创建奇数链表和偶数链表,并保存哨兵节点
        ListNode *oddList = head, *evenList = head->next;
        ListNode *oddHead = oddList, *evenHead = evenList;
        // 奇偶链表分别向后延伸两个节点,一直到当前next的节点为空
        while(oddList->next && evenList->next) {
            oddList->next = oddList->next->next;
            evenList->next = evenList->next->next;
            oddList = oddList->next;
            evenList = evenList->next;
        }
        // 奇数链表尾部挂接偶数链表
        oddList->next = evenHead;
        // 最终返回奇数链表
        return oddHead;
    }
};

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

****在这里插入图片描述


// 思路,找到head后面的n个节点作为post,head和post一起向后移动,当post的next为空时,head的next等于next->next,然后返回哨兵节点。我们可以找到中间的节点,就可以找到第n个点,也可以找到倒数第n个点

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if (head == nullptr || head->next == nullptr) {
            return nullptr;
        }
        ListNode *pHead = head, *post = head;
        ListNode *ret = pHead;

        while(n--) {
            post = post->next; // 找到第n个节点
        }
        if (post == nullptr) { // 如果是要删除第一个节点, 直接返回head->next, 这个有点打补丁
            return head->next;
        }

        while(post && post->next) { //  
            post = post->next;
            pHead = pHead->next;
        }
        
        pHead->next = pHead->next->next;
        return ret;
    }
};

148 排序链表

在这里插入图片描述

/*
思路:这题归根结底是排序,对数组排序可以用归并法,对链表排序其实也是可以用的。
1,找到链表的中点,将链表拆分成两个子链表。// 可以使用快慢指针法,返回slow的时候要保证无人指向slow,mid本身就是一个开始
2,对两个链表进行排序
3,合并 治法
延伸,分治法的思想
*/

// https://leetcode-cn.com/problems/sort-list/solution/c-an-bu-jiu-ban-qing-xi-de-gui-bing-pai-0cu85/
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == nullptr || head->next == nullptr)
            return head;
        ListNode* mid = middleNode(head);
        ListNode* left = sortList(head);
        ListNode* right = sortList(mid);
        return mergeTwoLists(left, right);
    }

    ListNode* middleNode(ListNode* head) {
        ListNode* fast = head, *slow = head;
        ListNode* prev = slow;
        while (fast && fast->next) {
            prev = slow;
            fast = fast->next->next;
            slow = slow->next;
        }
        prev->next = nullptr; // 让slow和head断了关系,slow在这里就是一个独立的节点了,无人指向mid
        return slow;
    }

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* head = new ListNode(0);
        ListNode* tail = head;

        while (l1 && l2) {
            if (l1->val <= l2->val) {
                tail->next = l1;
                l1 = l1->next;
            } else {
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
        }
        tail->next = l1 ? l1 : l2;
        return head->next;
    }

};

141 判断是不是环形链表

class Solution {

public:
    bool hasCycle(ListNode *head) {
        auto slow = head, fast = head;
        while(fast && fast->next)   // 保证非空
        {
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast)    return true;
        }
        return false; // 能走到这里说明其中一个走到了空
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值