链表高频面试算法题

以下是链表结构体:

/**
 * 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) {}
 * };
 */
链表排序 与 合并k个升序链表
  • 首先要搞定怎么合并两个升序链表,即下面的 mergetwolist函数,这个函数在后面的两个题解中都用的到
    // 将两个有序链表合成一个
    ListNode* mergeTwoLists(ListNode* h1, ListNode* h2) {
        if(!h1) return h2;
        if(!h2) return h1;
        ListNode *prehead = new ListNode(-1);
        ListNode *p = prehead;
        while(h1 && h2) {
            if (h1->val < h2->val) {
                p->next = h1;
                h1 = h1->next;
            } else {
                p->next = h2;
                h2 = h2->next;
            }
            p = p->next;
        }
        if(h1) p->next = h1;
        else p->next = h2;
        return prehead->next;
    }
  • Leetcode 题 : 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
    // 归并排序,快慢指针找中点,
    ListNode* sortList(ListNode* head) {
        if (!head || !head->next) return head;
        ListNode *slow = head, *fast = head;
        ListNode *prev;
        while (fast && fast->next) {
            prev = slow;            // 记得记住慢指针的上一步, 用于在中点切分链表
            slow = slow->next;
            fast = fast->next->next;
        }
        prev->next = NULL;   /// 从中点slow前 将链表切断
        return mergeTwoLists(sortList(head), sortList(slow));    归并的重点!!!
    }
 //merge :将 lists 中下标为l 到 下标为 r 之间[l,r]的链表合并
    ListNode* merge(vector<ListNode*>& lists, int l, int r) {
        if(l==r) return lists[l];
        int mid = l + (r-l)/2;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid+1, r));
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.empty()) return NULL;
        return merge(lists, 0, lists.size()-1);
    }
链表反转 — K 个一组翻转链表

通过此题可会做 链表翻转,链表部分翻转
Leetcode 题: 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

class Solution {
public:
    // 每次反转一段,然后将反转后这一段的末尾连到下一段反转后链表的头上
    ListNode* reverseKGroup(ListNode* head, int k) {
        if(!head) return NULL;
        ListNode *a = head, *b = head;
        int i = k;
        while (i > 0) {
            if(b == NULL) return head; // 不满 k 个就不反转
            b = b->next;
            i--;
        }
        // 反转 [a, b)之间的链表
        ListNode *newnode = revese(a, b);
        // 将b节点以后的链表也分段反转,并连在前一个反转链表的末尾。
        a->next = reverseKGroup(b, k); // 注意是将 a 连到 后面的节点
        return newnode;   // 注意不是返回 head, 而是 newnode
    }
    // 反转 [a, b) 之间的链表节点。2->3->4, 输出 4->3->2。
    ListNode *revese(ListNode *a, ListNode *b) {
        ListNode *prev, *cur, *nxt;
        prev = b, cur = a, nxt = a;
        while(cur != b) {
            nxt = cur->next;
            cur->next = prev;
            prev = cur;
            cur = nxt;
        }
        return prev;
    }
};
删除排序链表中的重复元素(去重 和 重复的元素全删)
  • Leetcode 题目: 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次,例如输入: 1->1->2->3->3,输出: 1->2->3 。
ListNode* deleteDuplicates(ListNode* head) {
        if(!head || !head->next) return head;
        ListNode *p = head;
        while(p && p->next) {
            if(p->val == p->next->val) {
                p->next = p->next->next;
            } else {
                p = p->next;
            }
        }
        return head;
    }
  • 牛客网题目 : 请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 。
ListNode* deleteDuplication(ListNode* pHead) {
        if(!pHead || !pHead->next) return pHead;
        ListNode *preh = new ListNode(-1);
        preh->next = pHead;
        ListNode *pre = preh, *cur = pHead;
        while(cur) {
            if (cur->next && cur->val == cur->next->val) {
                while (cur->next && cur->val == cur->next->val) {
                    cur = cur->next;
                }
                cur = cur->next;
                pre->next = cur;
            } else {
                pre = cur;
                cur = cur->next;
            }
        }
        return preh->next;
    }
奇偶链表

Leetcode题目 : 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

    // 把奇数编号的链表节点挂到Head后(odd遍历);
    //  把偶数链表节点挂到evenHead后(even遍历)
    //   最后把evenHead 挂到 odd后面。
    ListNode* oddEvenList(ListNode* head) {
        if (!head || !head->next) return head;
        ListNode *odd = head;
        ListNode *evenHead = head->next;
        ListNode *even = evenHead;
        while (even && even->next) {
            odd->next = even->next;
            odd = odd->next;
            even->next = odd->next;
            even = even->next;
        }
        odd->next = evenHead;
        return head;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值