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 的链表节点
- 解释:链表中有一个环,其尾部连接到第二个节点。
-
- 使用哈希表的方式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;
}
};
-
- 使用迭代的方式
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;
}
};