C++刷题模板之链表篇

C++刷题笔记

1、链表简介:

-1. 链表是一种物理存储单元上下不连续的存储结构,数据元素之间是通过链表中的指针进行链接。
-2. 链表有一系列的节点(链表中的每一个元素称为节点)组成,节点可以在运行时,动态生成。
-3. 每一个节点都包含两个部分:一个是存储数据的数据域,一个是存储下一个节点地址的指针域。
-4. 链表相对于数组:允许在任意位置进行插入或者删除节点,但是链表不支持随机访问节点,只能从头节点进行遍历访问每一个节点

2、链表的三种形式:

-1. 单向链表
- 包含两个域:一个数据域和一个指针域,它可以向一个方向遍历
-2. 双向链表
- 每个节点中有数据域和指针域(两个),前面的指针指向前一个节点,后一个指针指向下一个节点
-3. 循环链表
- 首节点和末节点被连在一起,它可以被视为“无头无尾”。这种链表比较有利于数据存储缓存。

3、有关链表的题(LeetCode精选 C++)

实战题目解析

链表的结构体
// 定义一个单向链表
Definition for singly-linked list.
struct ListNode {
     int val;
     ListNode *next;
     ListNode(int x) : val(x), next(NULL) {}
 };

1、206-Reverse-linked-list 反转链表 - Easy

  • 反转一个链表
    • 输入: 1 -> 2 -> 3 -> 4 -> 5 -> NULL
    • 输出: 5 -> 4 -> 3 -> 2 -> 1 -> NULL
// 采用双指针的方式:
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if( ! head)
            return nullptr; 
        ListNode* cur = nullptr; 
        ListNode* pre = head; 
        while(pre) {
            ListNode* last = pre->next; 
            pre ->next = cur; 
            cur = pre; 
            pre = last; 
        }
        return cur; 
    }
}

2、24-swap-nodes-in-pairs 两两交换链表中的节点 - Medium

  • 给定一个链表,两两交换其中的相邻的节点,并返回交换后的链表
    • 输入:head = [1, 2, 3, 4]
    • 输出:[2, 1, 4, 3]
  • 使用递归的方式:
class Solution {
public:
    // 使用递归的方式
    ListNode* swapPairs(ListNode* head) {
        if(!head || ! head ->next)
            return head; 
        ListNode* newhead = head -> next; 
        head ->next = swapPairs(newHead ->next); 
        newHead -> next = head; 
        return newHead; 
    }
};
  • 使用迭代的方式
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(!head)
            return nullptr; 
        ListNode* dummyHead = new ListNode(0);
        dummyHead ->next = head; 
        ListNode* pre = dummyHead; 
        while(pre ->next && pre ->next -> next) {
            ListNode* node1 = pre ->next; 
            ListNode* node2 = pre ->next -> next; 
            pre ->next = node2; 
            node1 ->next = node2 ->next; 
            node2 ->next = node1; 
            pre = node1; 
        }
        return dummyHead ->next; 
    }
};

3、141-linked-list-cycle 环形链表 - Easy

  • 给定一个链表,判断是否有环
    • 输入:head= [3, 2, 0, -4], pos = 1
    • 输出:true
    • 解释:链表中有一个环,其尾部连接到第二个节点
      -1. 利用set,几何进行节点的判重就行了
class Solution {
public:
//2.Times 
    // 使用set进行查重就行了
    // include<set>
    bool hasCycle(ListNode *head) {
        if(! head || ! head ->next)
            return false; 
        set<ListNode*>set_node; 
        while(head) {
            if(set_node.count(head))
                return true; 
            set_node.insert(head); 
            head = head ->next; 
        }
        return false; 
    }
};

-2. 使用双指针

class Solution {
public:
    bool hasCycle(ListNode* head) {
        if( !head || !head->next)
            return false; 
        ListNode* p_one = head; 
        ListNode* p_two = head ->next; 
        while(p_one && p_two) {
            if(p_two == p_one)
                retrun ture; 
            if(p_two -> next && p_two ->next ->next) {
                p_one  = p_one ->next; 
                p_two = p_two ->next ->next; 
            }
            else
                return false; 
        }
        return false; 
    }
};

4、142-linked-list-cycle-2 环形链表2 - Easy

  • 给定一个链表,返回链表入环的第一个节点,如果五环就返回null
    • 输入:head = [3,2,0,-4], pos = 1
    • 输出:返回索引为 1 的链表节点
    • 解释:链表中有一个环,其尾部连接到第二个节点。
    1. 使用哈希表的方式set
class Solution {
public:
  // 使用哈希表,set 进行求解的
    ListNode *detectCycle(ListNode *head) {
        if(!head)
            return nullptr; 
            set<ListNode*>set_p; 
        while(head) {
            if(set_p.count(head))
                return head; 
            set_p.insert(head); 
            head = head ->next; 
        }
        return nullptr; 
    }
};
    1. 使用迭代的方式
class Solution {
public:
// 使用迭代的方式。
// 利用双指针进行快慢的迭代,当相遇是就表示有环, 然后在重新迭慢指针
// 最后两个相遇的时候,就是入环的节点
    ListNode *detectCycle(ListNode *head) {
        if(! head || !head ->next)
            return nullptr; 
        ListNode* pre = head; 
        ListNode* fast = head ; 
        while(fast->next  && fast ->next ->next) {
            pre = pre ->next; 
            fast = fast ->next -> next;
            if(pre == fast) {
                ListNode* p = head; 
                while(p != fast) {
                    fast = fast ->next; 
                    p = p->next; 
                }
                return p; 
            }
        }
        return nullptr; 
    }
};

5、21-merge-two-sorted-lists 合并两个有序链表 - Easy

  • 将两个升序链表合并称为一个新的升序链表并返回,新链表是通过拼接给定的两个链表的所有的节点组成
    • 输入:L1 = [1, 2, 4], L2 = [1, 3, 4]
    • 输出:[1, 1, 2, 3, 4, 4]
  • 使用递归的方式
class Solution {
public:
    // 使用递归的方式
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(!l1) 
            return l2; 
        else if( !l2)
            return l1; 
        else if( l1->val < l2->val) {
            l1->next = mergeTwoLists(l1 ->next, l2);
            return l1; 
        } 
        else {
            l2->next = mergeTwoLists(l1, l2 ->next); 
            return l2; 
        }
    }
};
  • 使用迭代的方式
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* head = new ListNode(0); 
        ListNode* cur = head;
        while(l1 && l2) {
            if(l1 ->val <= l2 ->val) {
                cur ->next = l1; 
                l1 = l1 ->next; 
                //cur = cur ->next; 
            }
            else {
                cur ->next = l2; 
                l2 = l2 ->next; 
                //cur = cur ->next; 
            }
            cur = cur ->next; 
        }
        cur ->next = l1==nullptr? l2 :l1; 
        return head ->next; 
    }
};

6、 147-insertion-sort-list 对链表进行插入排序 - Medium

  • 对链表进行插入排序
    • 输入:4 -> 1 -> 2 -> 3
    • 输出;1 -> 2 -> 3 -> 4
class Solution {
public:
    ListNode* insertionSortList(ListNode* head) {
            if(! head)
                return nullptr; 
            ListNode* dummyHead = new ListNode(0);
            dummyHead ->next = head; 
            ListNode* last = head;  // 表示当前的正确顺序的最后一个节点
            ListNode* cur = head->next; 
            while(cur ) {
                if(last ->val <= cur ->val) 
                    last = last ->next; 
                else {
                    ListNode* pre = dummyHead; 
                    while(pre ->next ->val <= cur ->val )
                        pre = pre ->next; 
                    last ->next = cur ->next; 
                    cur ->next = pre ->next; 
                    pre ->next = cur; 
                }
                cur = last ->next; 
            }
            return dummyHead ->next; 
    }
};

7、 25-recerse-nodes-in-k-group k个一组翻转链表 - Hard

  • 给定一个链表,每k个节点为一组进行翻转,请返回翻转后的链表
  • k是一个正整数,他的值小于或者等于链表的长度
  • 如果节点总数不是k的整数倍,那么请将最后剩下的节点保持原有的顺序
    • 输入:head = [1, 2, 3, 4, 5], k = 3
    • 输出:[3, 2, 1, 4, 5]
calss Solution {
public:
    // 直接将第k个节点之前的节点依次进行插入到第k个节点前面
    ListNode* reverseKGroup(ListNode* head, int k0 {
        if(!head)
            return nullptr; 
        if(k == 1)
            return head;
        ListNode* dummyHead = new ListNode(-1); 
        dummyHead ->next = head; 
        ListNode* pre = dummyHead; 
        ListNode* cur = pre; 
        // 一个计算的变量,与k做比较
        int counts = 0; 
        while(cur) {
            ++ counts; 
            cur = cur -> next; 
            if(counts == k && cur) {
                ListNode* last = pre -> next; 
                // 进行顺序的插入节点
                while(-- counts) {
                    ListNode* temp = pre ->next; 
                    pre ->next = temp ->next; 
                    temp ->next = cur -> next; 
                    cur ->next = temp; 
                }
                pre = cur = last; 
            }
        }
        return dummyHead -> next; 
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值