1、使用常量空间复杂度在O(n log n)时间内对链表进行排序。

思路:

因为题目要求复杂度为O(nlogn),故可以考虑归并排序的思想。
归并排序的一般步骤为:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。
 
所以对应此题目,可以划分为三个小问题:
1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);
2)写出merge函数,即如何合并链表。 (见merge-two-sorted-lists 一题解析)
3)写出mergesort函数,实现上述步骤。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
//找到链表中的中点
ListNode *findMiddle(ListNode *head){
ListNode *chaser = head;
ListNode *runner = head->next;
while(runner !=NULL &&runner->next != NULL){
chaser = chaser->next;
runner = runner->next->next;
}
return chaser;
}
//将两组链表进行排序
ListNode *mergeTwoLists(ListNode* l1, ListNode* l2){
if(l1==NULL) return l2;
if(l2==NULL) return l1;
ListNode *dummy = new ListNode();
ListNode *head = dummy;
while(l1!=NULL && l2!=NULL){
if(l1->val > l2->val){
head->next = l2;
l2 = l2->next;
}else{
head->next = l1;
l1 = l1->next;
}
head = head->next;
}
if(l1==NULL) head->next = l2;
if(l2==NULL) head->next = l1;
return dummy->next;
} ListNode *sortList(ListNode *head) {
if(head==NULL || head->next == NULL) return head;
ListNode* middle = findMiddle(head);
ListNode* right = sortList(middle->next);
middle -> next = NULL;
ListNode* left = sortList(head);
return mergeTwoLists(left, right);
}
};

2、给出单链表L:L 0→L 1→...→L n-1→L n,

将其重新排序为:L 0→L n→L 1→L n-1→L 2→L n-2→......
您必须在不改变节点值的情况下就地执行此操作。
例如,
给定{1,2,3,4},将其重新排序为{1,4,2,3}。

思路:快慢指针找到中间节点,将后面的链表反转(前插法),合并链表

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
//快慢指针找到中间节点
while(fast->next!=NULL && fast->next->next!=NULL){
slow = slow->next;
fast = fast->next->next;
}
//拆分链表,并反转中间节点之后的链表
ListNode *after = slow->next;
slow->next = NULL;
ListNode *pre = NULL;
while(after!=NULL){
ListNode *temp = after->next;
after->next = pre;
pre = after;
after = temp;
}
// 合并两个表
ListNode *left = head;
after = pre;
while(left!=NULL && after!=NULL){
ListNode *ltemp = left->next;
ListNode *rtemp = after->next;
left->next = after;
left = ltemp;
after->next = left;
after = rtemp;
}
}
};

3、给定链表,返回循环开始的节点。 如果没有循环,则返回null。
跟进:
你能不用额外的空间解决它吗?

思路:

1)首先判断是否有环,有环时,返回相遇的节点,无环,返回null
2)有环的情况下, 求链表的入环节点
从头结点开始走,一边走一边将走过的路清空,当遇到空时,此时就是环的入口点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
//找到相遇点
while(fast!=NULL && fast->next!=NULL){
slow=slow->next;
fast=fast->next->next;
//如果快慢指针相遇
if(slow==fast){
ListNode *temp = NULL;
//一边走一边将走过的路清空,当遇到空时,此时就是相遇点
while(head->next){
temp = head->next;
head->next = NULL;
head = temp;
}
return head;
}
}
return NULL;
}
};

4、给定一个链表,确定它是否有一个循环。
跟进:
你能不用额外的空间解决它吗?

思路:

利用快慢节点相遇即有环,

慢节点一次走一格

快捷点一次走两格

/**
* 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 *slow = head;
ListNode *fast = head;
//找到相遇点
while(fast!=NULL && fast->next!=NULL){
slow=slow->next;
fast=fast->next->next;
//如果快慢指针相遇
if(slow==fast) return true;
}
return false;
}
};

5、给出链表,使得每个节点包含一个附加的随机指针,该指针可以指向列表中的任何节点或为空。
返回列表的深层副本。

思路:

先拷贝新节点,插入到原节点的后边;然后再 拷贝随机指针;最后将新节点从原链表中分离出,注意要保证原链表正常。

/**
* Definition for singly-linked list with a random pointer.
* struct RandomListNode {
* int label;
* RandomListNode *next, *random;
* RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
* };
*/
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
RandomListNode *p,*copy;
if (!head) return NULL;
//先将拷贝原节点产生的新节点,放在原节点的后面
for(p=head;p;p=p->next){
copy = new RandomListNode(p->label);
copy->next = p->next;
p = p->next = copy;
}
//拷贝random指针
for(p=head;p;p=copy->next){
copy = p->next;
copy->random = (p->random?p->random->next:NULL);
}
//删除新节点
for(p=head,head=copy=p->next;p;){
p = p->next = copy->next;
copy = copy->next = (p?p->next:NULL);
}
return head;
}
};

6、将位置m的链接列表反转到n。 在原地和一次通过。
例如:
给定1-> 2-> 3-> 4-> 5-> NULL,m = 2且n = 4,
return1->4->3-> 2->5-> NULL。
注意:
给定m,n满足以下条件:
1≤m≤n≤列表长度。

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *reverseBetween(ListNode *head, int m, int n) {
ListNode *dummy = new ListNode(-);
ListNode *preStart,*Start;
dummy->next = head;
preStart = dummy;
Start = head;
for(int i=;i<m;i++){
preStart = Start;
Start = Start->next;
}
for(int i=;i<n-m;i++){
ListNode *temp = Start->next;
Start->next = temp->next;
temp->next = preStart->next;
preStart->next = temp;
}
return dummy->next;
}
};

7、给定链表和值x,对其进行分区,使得小于x的所有节点都在大于或等于x的节点之前。
您应该保留两个分区中每个分区中节点的原始相对顺序。
例如,
给定1-> 4-> 3-> 2-> 5-> 2和x = 3,
return1-> 2->2->4->3->5。

思路:

创建两张链表,分别我list01和list01

把节点值小于x的节点链接到链表1上,节点值大等于x的节点链接到链表2上。

最后把两个链表相连即可
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *partition(ListNode *head, int x) {
//创建两个链表
ListNode *list01 = new ListNode(-);
ListNode *list02 = new ListNode(-);
ListNode *cur1 = list01;
ListNode *cur2 = list02;
while(head!=NULL){
//把节点值小于x的节点链接到链表1上
if(head->val < x){
cur1->next = head;
cur1=cur1->next;
}
//节点值大等于x的节点链接到链表2上
else{
cur2->next = head;
cur2=cur2->next;
}
head = head->next;
}
//合并两个链表
cur1->next = list02->next;
cur2->next = NULL;
return list01->next;
} };

8、给定一个列表,将列表向右旋转k个位置,其中k为非负数。

例如:
给定1-> 2-> 3-> 4-> 5-> NULL和k = 2,
返回4-> 5-> 1-> 2-> 3-> NULL。

思路:

先遍历一遍,得出链表长度len,注意k可能会大于len,因此k%=len。
将尾结点next指针指向首节点,形成一个环,接着往后跑len-k步,从这里断开,就是结果
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *rotateRight(ListNode *head, int k) {
if(head==NULL) return NULL;
ListNode *p=head;
int len=;
//计算连链表的长度
while(p->next){
len++;
p=p->next;
}
k = len - k%len;
//首尾相连
p->next = head;
for(int i=;i<k;i++){
p=p->next;
}
head = p->next;
p->next = NULL;
return head;
}
};

9、给定已排序的链接列表,删除所有具有重复数字的节点,只留下原始列表中的不同数字。

例如,
给定1-> 2-> 3-> 3-> 4-> 4-> 5,返回1-> 2-> 5。
给定1-> 1-> 1-> 2-> 3,return2-> 3。

思路:

首先要找到第一个非重复的节点作为头结点,
直接找比较麻烦,可以添加一个新结点list作为伪头结点,
最后返回list->next即可。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *deleteDuplicates(ListNode *head) {
if(head==NULL) return NULL;
ListNode *list = new ListNode(head->val-);
list->next = head;
ListNode *preStart = list;
while(preStart->next && preStart->next->next){
ListNode *Start = preStart->next;
ListNode *aftStart = Start->next;
if(Start->val!=aftStart->val){
preStart->next = Start;
preStart = Start;
}else{
while(aftStart && Start->val==aftStart->val){
aftStart=aftStart->next;
}
preStart->next = aftStart;
}
}
return list->next;
}
};

10、给定已排序的链接列表,删除所有重复项,使每个元素只出现一次。

例如,
给定1-> 1-> 2,return1-> 2。
给定1-> 1-> 2-> 3-> 3,返回1-> 2-> 3。

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *deleteDuplicates(ListNode *head) {
if(head == NULL || head->next == NULL) return head;
ListNode* p1 = head;
while(p1 != NULL && p1->next != NULL) {
ListNode* p2 = p1->next;
if(p1->val != p2->val) {
p1->next = p2;
p1 = p1->next;
continue;
}
while(p2->next != NULL && p1->val == p2->next->val)
p2 = p2->next;
p1->next = p2->next;
delete p2;
p1 = p1->next;
}
return head;
}
};

11、合并两个已排序的链接列表并将其作为新列表返回。 新列表应该通过拼接前两个列表的节点来完成。

思路:和归并排序的思想一样

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
ListNode *head = new ListNode();
ListNode *t = head;
while (l1 != NULL || l2 != NULL) {
if (l1 == NULL) {
t->next = l2;
l2 = l2->next;
}
else if (l2 == NULL) {
t->next = l1;
l1 = l1->next;
}
else if (l1->val < l2 -> val){
t->next = l1;
l1 = l1->next;
}
else {
t->next = l2;
l2 = l2->next;
}
t = t->next;
}
return head->next;
}
};

12、给定链表,一次反转链表k的节点并返回其修改后的列表。
如果节点数不是k的倍数,那么最后的剩余节点应该保持不变。
您可能无法更改节点中的值,只能更改节点本身。
只允许常量内存。
例如,
鉴于此链表:1-> 2-> 3-> 4-> 5
对于k = 2,您应该返回:2-> 1-> 4-> 3-> 5
对于k = 3,您应该返回:3-> 2-> 1-> 4-> 5

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *reverseKGroup(ListNode *head, int k) {
/*
if(head==NULL || head->next==NULL || k<2) return head;
ListNode *dummy = new ListNode(-1);
dummy->next = head;
ListNode *Start = head;
ListNode *preStart = dummy;
ListNode *temp;
int len = 1;
while(head!=NULL){
len++;
head=head->next;
}
for(int i=0;i<len/2;i++){
for(int j=i+1;j<len;j++){
temp = Start->next;
Start->next = temp->next;
temp->next = preStart->next;
preStart->next = temp;
}
preStart = Start;
Start = Start->next;
}
return dummy->next;
*/
if(head == NULL || head->next == NULL || k < ) return head;
ListNode *dummy = new ListNode(-);
dummy->next = head;
ListNode *pre = dummy, *cur = head, *temp;
int len = ;
//计算链表的长度
while (head != NULL) {
len ++ ;
head = head->next;
}
for (int i = ; i < len / k; i ++ ) {
for (int j = ; j < k; j ++ ) {
temp = cur->next;
cur->next = temp->next;
temp->next = pre->next;
pre->next = temp;
}
pre = cur;
cur = cur->next;
}
return dummy->next;
}
};

13、给定链表,交换每两个相邻节点并返回其头部。
例如,
给定1-> 2-> 3-> 4,您应该返回列表as2-> 1-> 4-> 3。
您的算法应该只使用恒定空间。 您可能无法修改列表中的值,只能更改节点本身。

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *swapPairs(ListNode *head) {
if(head==NULL || head->next==NULL ) return head;
ListNode *dummy = new ListNode(-);
dummy->next = head;
ListNode *Start = head;
ListNode *aftStart = head->next;
ListNode *preStart = dummy;
ListNode *temp;
while(Start!=NULL && aftStart!=NULL){
temp = aftStart->next;
Start->next = temp;
aftStart->next = Start;
preStart->next = aftStart;
preStart = Start;
Start = temp;
aftStart = temp->next;
}
return dummy->next;
}
};

14、给定链表,从列表末尾删除第n个节点并返回其头部。
例如,
给定链表:1-> 2-> 3-> 4-> 5,n = 2。
从末尾删除第二个节点后,链表变为1-> 2-> 3-> 5。
注意:
给定n将始终有效。
尝试一次性完成此操作。

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *removeNthFromEnd(ListNode *head, int n) {
if(head==NULL ) return head;
ListNode *dummy = new ListNode();
dummy->next = head;
head = dummy;
ListNode *slow = head;
ListNode *fast = head;
for(int i=;i<n;i++){
fast = fast->next;
}
while(fast->next!=NULL){
fast = fast->next;
slow = slow->next;
}
ListNode *temp = slow->next;
slow->next = slow->next->next;
delete temp;
return dummy->next;
}
};

LeetCode--链表的更多相关文章

  1. [LeetCode] [链表] 相关题目总结

    刷完了LeetCode链表相关的经典题目,总结一下用到的技巧: 技巧 哑节点--哑节点可以将很多特殊case(比如:NULL或者单节点问题)转化为一般case进行统一处理,这样代码实现更加简洁,优雅 ...

  2. Leetcode链表

    Leetcode链表 一.闲聊 边学边刷的--慢慢写慢慢更 二.题目 1.移除链表元素 题干: 思路: 删除链表节点,就多了一个判断等值. 由于是单向链表,所以要删除节点时要找到目标节点的上一个节点, ...

  3. [LeetCode] 链表反转相关题目

    暂时接触到LeetCode上与链表反转相关的题目一共有3道,在这篇博文里面总结一下.首先要讲一下我一开始思考的误区:链表的反转,不是改变节点的位置,而是改变每一个节点next指针的指向. 下面直接看看 ...

  4. LeetCode链表解题模板

    一.通用方法以及题目分类 0.遍历链表 方法代码如下,head可以为空: ListNode* p = head; while(p!=NULL) p = p->next; 可以在这个代码上进行修改 ...

  5. LeetCode链表相加-Python<二>

    上一篇:LeetCode两数之和-Python<一> 题目:https://leetcode-cn.com/problems/add-two-numbers/description/ 给定 ...

  6. leetcode 链表类型题总结

    链表测试框架示例: // leetcodeList.cpp : 定义控制台应用程序的入口点.vs2013 测试通过 // #include "stdafx.h" #include ...

  7. leetcode链表相关

    目录 2/445两数相加 综合题(328奇偶链表, 206反转链表, 21合并两个有序链表 ) 92反转链表 II 链表排序(148排序链表, 876链表的中间结点) 142环形链表 II 160相交 ...

  8. LeetCode 链表题 ( Java )

    leetcode 237. 删除链表中的节点 链接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list/ 示例 : 输入: he ...

  9. LeetCode 链表的插入排序

    Sort a linked list using insertion sort 创建一个新的链表,将旧链表的节点插入到正确的位置 package cn.edu.algorithm.huawei; pu ...

  10. leetcode 链表类型题目解题总结

    最基础的方式要做到非常熟练,要熟练到不思考就能写,但又需明白各处的要求和陷阱 合并两个有序链表的操作,在前面加上一个初始节点,注意while循环和退出时的处理,理解如何处理其中一个链表遍历完的情况 L ...

随机推荐

  1. C#登录SSH执行命令,下载文件

    前言 批量登录SSH执行命令 ,把应急响应中的日志文件下载回来. 代码实现 Renci.SshNet编译出DLL,引用. using System; using System.Collections. ...

  2. 是什么在阻止我们学习unity2019?

    背景 时过境迁,这是一篇老文,写于2019年5月. 在学习最新的unity ecs过程中,以及学习最新的effect 时,在迈出第一步的时候即遭遇一些困难(学习和测试环境搭建不起来,有时候真的很无语) ...

  3. Zuul1与Spring Cloud Gateway对比

    一.API网关 1.1 Zuul1简介 1.2 Spring Cloud Gateway简介 二.对比 2.0 产品对比 2.1 性能对比 2.1.1 低并发场景 2.1.2 高并发场景 2.1.3 ...

  4. yum源出问题,rpmdb: BDB0113 Thread/process 17276/140338032428864 failed: BDB1507 Thread died in Berkeley DB library

    yum源出问题 cd /var/lib/rpm rm -f *db.* rpm --rebuilddb 重构了之后就可以用了

  5. SC创建服务编写bat脚本

    新建bat脚本,并写入一下文本保存 sc create "DevFast.SupportGPSWarmService" binpath= "%cd%\DevFast.Su ...

  6. 什么是HybridDB for MySQL (原PetaData)

    云数据库HybridDB for MySQL (原名PetaData)是同时支持海量数据在线事务(OLTP)和在线分析(OLAP)的HTAP(Hybrid Transaction/Analytical ...

  7. 利用Python进行数据分析_Pandas_基本功能

    申明:本系列文章是自己在学习<利用Python进行数据分析>这本书的过程中,为了方便后期自己巩固知识而整理. 第一 重新索引 Series的reindex方法 In [15]: obj = ...

  8. Python笔记day20-面向对象

    目录 面向对象 1 装饰器 1.1 装饰器是什么? 1.2 装饰器 2 面向对象 (Object Oriented) 简称OO 2.1 面向对象相关术语 2.2 类和对象 2.3 类和对象的实现和书写 ...

  9. 【BFS】Help the Princess!

    题目描述 The people of a certain kingdom make a revolution against the bad government of the princess. T ...

  10. (转) 从0移植uboot(五) _实现串口输出

    ref : https://www.cnblogs.com/xiaojiang1025/p/6500520.html 串口作为一种非常简单的通信方式,才是嵌入式系统调试的王道,通过设置串口输出,我们可 ...