链表相关题目整理
求链表的倒数第k个节点
思路:两个指针同时指向head,第一个指针先走k-1步,然后两个指针同时移动,当第一个指针走到尾节点时,第二个指针指向的就是倒数第k个节点(这里使两个指针的距离和倒数第一个与倒数第k个节点距离相同即可),当然也需要考虑边界问题,如小于等于0,倒数第k个节点大于链表节点
Node* FindKthToTail(Node *head,int k)
{
if(head == NULL || k <= 0)
return;
Node *pFirst = head;
Node *pSecond = head;
for(auto i = 0;i < k - 1;++i)
{
//倒数第k个大于链表节点
if(pFirst == NULL)
return NULL;
pFirst = pFirst ->next;
}
while(pFirst->next != NULL)
{
pFirst = pFirst ->next;
pSecond = pSecond ->next;
}
return pSecond ;
}
两个有序链表的合并
思路:刷题看到题解说了一种伪头结点的方法,这思路确实让题目变得简单易懂,仅仅是使用了一个辅助节点
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *res = new ListNode(0), *p = res;
while(l1 && l2 ){
l1->val < l2->val ? (p->next = l1,l1 = l1->next) : (p->next = l2, l2 = l2->next);
p = p->next;
}
//判断哪条链表先遍历到了尾节点
p->next = l1 ? l1 : l2;
return res->next;
}
};
递归
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1 == nullptr)
return l2;
if(l2 == nullptr)
return l1;
if(l1->val < l2->val)
{
l1->next = mergeTwoLists(l1->next,l2);
return l1;
}
else
{
l2->next = mergeTwoLists(l1,l2->next);
return l2;
}
}
};
两条单链表是否相交以及交点(不考虑单链表有环)
思路:1.暴力双循环遍历,当然效率也是最低。时间复杂度O(n²)
2.遍历两条链表分别求出长度为len1,len2,然后求出两者之差,较长的链表先移动|len1 - len2|。接着两条链表同时遍历
3.两条链表分别入栈,判断栈顶元素是否相同,相同则分别出栈直到栈顶元素不同为止
思路2:
Node *Intersect(Node *list1,Node *list2)
{
if(list1 == NULL || list2 == NULL)
return NULL;
Node *pTemp1 = list1;
Node *pTemp2 = list2;
int len1 = 1,len2 = 1;
while(pTemp1 ->next != NULL)
{
pTemp1 = pTemp1->next;
len1++;
}
while(pTemp2 ->next != NULL)
{
pTemp2 = pTemp2->next;
len2++;
}
if(pTemp1 != pTemp2)
return NULL;
pTemp1 = list1;
pTemp2 = list2;
if(len1 > len2)
{
int diff = len1 - len2;
for(auto i = 0;i < diff;++i)
{
pTemp1 = pTemp1->next;
}
}
else if (len1 < len2)
{
int diff = len2 - len1;
for(auto i = 0;i < diff;++i)
{
pTemp2 = pTemp2->next;
}
}
while(pTemp1 != pTemp2)
{
pTemp1 = pTemp1->next;
pTemp2 = pTemp2->next;
}
return pTemp1;
}
思路3:
Node *Intersect(Node *list1,Node *list2)
{
if(list1 == NULL || list2 == NULL)
return;
stack<Node> s1;
stack<Node> s2;
while(list1 != NULL)
{
s1.push(list1);
list1 = list1->next;
}
while(list2 != NULL)
{
s2.push(list2);
list2 = list2->next;
}
if(s1.top() != s2.top())
return NULL;
Node *temp = NULL;
while(!s1.empty() && !s2.empty())
{
temp = s1.top();
s1.pop();
s2.pop();
if(s1.top() != s2.top())
break;
}
return temp;
}
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
方法一
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr) return nullptr;
Node* cur = head;
unordered_map<Node*, Node*> map;
// 3. 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
while(cur != nullptr) {
map[cur] = new Node(cur->val);
cur = cur->next;
}
cur = head;
// 4. 构建新链表的 next 和 random 指向
while(cur != nullptr) {
map[cur]->next = map[cur->next];
map[cur]->random = map[cur->random];
cur = cur->next;
}
// 5. 返回新链表的头节点
return map[head];
}
};
方法二
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr)
return nullptr;
Node* cur = head;
// //将拷贝节点放到原节点后面,例如1->2->3这样的链表就变成了这样1->1'->2->2'->3->3'
while(cur != nullptr) {
Node* tmp = new Node(cur->val);
tmp->next = cur->next;
cur->next = tmp;
cur = tmp->next;
}
// 2. 把拷贝节点的random指针安排上
cur = head;
while(cur != nullptr) {
if(cur->random != nullptr)
cur->next->random = cur->random->next;
cur = cur->next->next;
}
// 3. 分离拷贝节点和原节点,变成1->2->3和1'->2'->3'
cur = head;
Node* res = head->next, *temp = nullptr;
while(cur != nullptr && cur->next != nullptr)
{
temp = cur->next;
cur->next = temp->next;
cur = temp;
}
return res; // 返回新链表头节点
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律