解法:这个比较容易,直接对比两个两个链表节点,小的节点直接插入到返回的新链表上
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead1 ListNode类
* @param pHead2 ListNode类
* @return ListNode类
*/
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
ListNode* dummy = new ListNode(0);
ListNode* p = dummy;
if(pHead1 ==nullptr){
return pHead2;
}
if(pHead2 == nullptr){
return pHead1;
}
while (pHead1 && pHead2) {
if(pHead1->val > pHead2->val){
p->next = pHead2;
p = p->next;
pHead2= pHead2->next;
}
else {
p->next = pHead1;
p= p->next;
pHead1= pHead1->next;
}
}
if(pHead1 ==nullptr){
p->next = pHead2;
}
if(pHead2==nullptr){
p->next = pHead1;
}
return dummy->next;
}
};
解法:这个稍微复杂一些,需要找到k个链表中节点的最小值。所以我们需要借助优先队列(小根堆),先获取每个链表的第一个节点的大小关系,然后获取当前最小节点链表的后续节点加入到队列。依赖优先队列的自动排序的特性,很容易获得从小到大的链表。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include
#include
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param lists ListNode类vector
* @return ListNode类
*/
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.size() == 0) return nullptr;
// 申请虚拟头节点,需要传出函数。
ListNode* dummy = new ListNode(-1);
ListNode* p = dummy;
// 重载比较方式
struct cmp {
bool operator()(ListNode* a, ListNode* b) {
return a->val > b->val;
}
};
// 队列里存放的是链表的头指针,并按照我们自定义的方式排序。
priority_queue<ListNode*, vector<ListNode*>, cmp> pq;
for (int i = 0; i < lists.size(); ++i) {
if (lists[i] != nullptr) { // 需要考虑到空的链表
pq.push(lists[i]);
}
}
while (!pq.empty()) {
ListNode* temp = pq.top();
pq.pop();
p->next = temp;
p = p->next;
// 如果当前最小节点的链表后续有节点,加入到队列中排序,这样
// 就可以得到当前最小的节点
if (temp->next) {
pq.push(temp->next);
}
}
return dummy->next;
}
};
或者,你可以把所有链表节点值摘下来,放到优先队列里排序(或者你放数组里然后排序都行),然后再重新建立链表
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode* dummy = new ListNode(-1);
ListNode* p = dummy;
priority_queue<int, vector<int>, greater<int>> pq;
for (int i = 0; i < lists.size(); ++i) {
if (lists[i] != nullptr) {
while (lists[i]) {
pq.push(lists[i]->val);
lists[i] = lists[i]->next;
}
}
}
while (!pq.empty()) {
// 需要重新申请节点,否则无法连接
p->next = new ListNode(pq.top());
pq.pop();
p = p->next;
}
return dummy->next;
}
解法:这道题,有同学可能采用暴力解法,把链表节点依次放入到数组中,每放入一个就遍历数组查看是否存在该节点,如果存在就有环,否则没有。这样的确可以通过,但是速度会大大折扣,我们这里采用快慢指针的思想。快慢指针,故名思意一个指针走的快,一个走得慢,如果两个指针同时从链表头部开始走,如果有环一定会在某个地方相遇。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast = head;
ListNode *slow = head;
// 注意这里,快指针在没有环的情况下,最先到达表尾,且要排除单个节点无环情况
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
return true;
}
}
return false;
}
};
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
ListNode* slow = pHead, *fast = pHead;
// 大于一个节点才能算环
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
break;
}
}
// 无环情况
if (fast == nullptr || fast->next == nullptr) return nullptr;
fast = pHead;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return fast;
}
};
还可以采用哈希来解答,把节点依次加入到哈希中,如果某个元素重复了,那么即为入口。
#include
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
unordered_set<ListNode*>set;
while(pHead){
if(set.count(pHead)) return pHead; // 也可以使用contains(c++20)
set.insert(pHead);
pHead = pHead->next;
}
return nullptr;
}
};
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode * dummy =new ListNode(-1);
dummy->next = head;
ListNode* p1 = dummy, * p2 = dummy;
if (head == nullptr) return nullptr;
// 快指针先走n步
while (n--) {
p2 = p2->next;
}
// 同时走,直到链表结尾
while (p2->next) {
p1 = p1->next;
p2 = p2->next;
}
// 删除节点
p1->next = p1->next->next;
return dummy->next;
}
};
4.判断两个链表是否相交,相交则返回相交节点
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode* L1 = pHead1, *L2 = pHead2;
while (L1 != L2) {
L1 = (L1 == nullptr) ? pHead2 : L1->next;
L2 = (L2 == nullptr) ? pHead1 : L2->next;
}
return L1;
}
};
同样也可以用哈希做,但会产生额外空间,同前所述。
解法:双指针法,两个指针开始都指向头节点,当后续节点值相同时,快指针向后移动,满指针不动。当节点值不同时,当前慢指针的next指向快指针,然后移动到快指针节点处。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (head == nullptr) return nullptr;
ListNode* fast = head, *slow = head;
while (fast) {
if (fast->val == slow->val) {
fast = fast->next;
} else {
slow ->next = fast;
slow = fast;
}
}
slow->next = nullptr;
return head;
}
};
解法:本题是上一道题的进阶版,上一题删除元素让所有元素只出现一次,这道题是,将所有重复的删除。最常规的还是双指针法,一个指针遍历的元素,并设置标志位,标记元素是否重复,一个指针偏移
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include
#include
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* dummy = new ListNode(-1);
if (head == nullptr) return nullptr;
dummy->next = head;
bool single = true; // 元素是否是只有一个
ListNode* p1 = dummy, *p2 = head;
while(p2->next){
// 如果p2的当前值和下一个值相同就标记这个元素不是唯一,并移动p2
if(p2->val == p2->next->val){
single = false;
p2=p2->next;
}
// 当p2与后面的值不同时,需要判断p2当前指定的值是否是唯一的,
// 如果不是唯一的,p1的next指向p2的next(注意,此时不移动p1),实现删除重复元素,并重置标记
// 如果是唯一的,保留元素,那么p1指向p2,并移动到p2,然后p2指向下一个节点。
else {
if(!single){
p1->next = p2->next;
p2 = p2->next;
single = true;
}
else {
p1->next = p2;
p1 = p2;
p2= p2->next;
}
}
}
// 出现重复元素后面无其它元素时。
if(!single){
p1->next = nullptr;
}
return dummy->next;
}
};
解法2:其实这道题还可以使用哈希来做,记录元素出现次数大于1的元素,并删除,重新建立链表
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr )return nullptr;
unordered_map<int,int>map;
ListNode *dummy = new ListNode(-1);
dummy->next = head;
ListNode* cur = head;
// 统计每个元素出现的次数。
while(cur){
map[cur->val]++;
cur = cur->next;
}
cur = dummy;
// 重新建立链表
while(cur->next){
if(map[cur->next->val] != 1){
cur->next = cur->next->next;
}else {
cur = cur->next;
}
}
return dummy->next;
}
};
解法:前面我们使用了大量的双指针来解题,这个同样可以用双指针来解决,但是由于是单链表,所以我们需要借助数组,来存储元素,然后使用两个指针从数组的两边来对比元素。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) : val(x), next(nullptr) {}
* };
*/
#include
class Solution {
public:
bool isPail(ListNode* head) {
vector<int>vec;
while (head) {
vec.push_back(head->val);
head = head->next;
}
int p = vec.size() - 1;
for (int i = 0; i < (vec.size() - 1) / 2; ++i) {
if (vec[i] != vec[p - i]) {
return false;
}
}
return true;
}
};