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. AWS 存储服务(三)

    目录 AWS S3 业务场景 挑战 解决方案 S3的好处 S3 属性 存储桶 Buckets 对象 Object S3 特性 S3 操作 可用性和持久性 一致性 S3 定价策略 S3高级功能 存储级别 ...

  2. sed练习,一些sed常用方法

    1.复制/etc/rc.d/rc.local 文件至/tmp目录,将/tmp/rc.sysinit文件中的以至少一个空白字符开头的行的行首加#. sed -ri 's/^ +/#/g'  rc.loc ...

  3. element-ui中的表格嵌套表格

    element-ui中有详细的各种表格及表格方法.也有表格展开出现二级的样式,但是却没有表格嵌套二级表格的方案,于是就自己写了一个,样式图如下: 展开后如下 这就是一个普通的二级表格嵌套,用的是el- ...

  4. React native 放大点击区域 hitSlop属性的使用

    在日常的需求中,如上图的加减按钮,可能写ui布局的时候没考虑实际的这个点击范围太小,不利于真机上用户点击到,如果加包裹层加padding的话又会影响原先定好的布局,或者不利于对齐. 那么可以用  hi ...

  5. 【转载】spring mvc 后端获得前端传递过来的参数的方法

    1.通过HttpServletRequest 获得 HttpServletRequest.getParameter(参数名),可以获得form表单中传递的参数,或ajax或url中传递过来的参数,如果 ...

  6. 【学习笔记】RMQ-Range Minimum/Maximum Query (区间最小/最大值)

    RMQ是一类询问区间最小/最大值的问题. 这类问题一般分成两类:静态区间(无修改),动态区间(带修改). 对于动态区间查询最大/最小,我们显然可以用线段树来解决…… 那么对于静态区间查询最大/最小的问 ...

  7. 切片(Slice)

    Python提供了切片(Slice)操作符:可以一次取出多个列表元素 L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3.0可以省略:L[:3] L[:]:就是整个列表   补充: 前1 ...

  8. 20191011-构建我们公司自己的自动化接口测试框架-Util的htmlreport模块

    生成htmlreport的模块是我在网上随意找的一个版本,主要生成的report包括接口名称,接口url,请求数据,响应数据,断言词,断言结果等 具体的htmlreport代码如下: # -*- en ...

  9. 1261: 单位转换(Java)

    WUSTOJ 1261: 单位转换 参考资料 数字字符串拆分--百度知道 Description BobLee最近在复习考研,在复习计算机组成原理的时候,遇到了一个问题.就是在计算机存储里面的单位转换 ...

  10. AttnGAN: Fine-Grained Text to Image Generation with Attentional Generative Adversarial Networks 笔记

    AttnGAN: Fine-Grained Text to Image Generation with Attentional Generative Adversarial Networks 笔记 这 ...