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. Vector3.Angle问题

    Angle角度 public static float Angle(Vector3 from, Vector3 to); 返回的角度总是两个向量之间的较小的角(实测返回不大于 180 度, 并不是 u ...

  2. 打印网页js

    ====================================设置打印样式 <style media="print"> .Noprint { display: ...

  3. Redis ZSet 有序集合

    有序集合类型与集合类型的区别就是他是有序的.有序集合是在集合的基础上为每一个元素关联一个分数,这就让有序集合不仅支持插入,删除,判断元素是否存在等操作外,还支持获取分数最高/最低的前N个元素.有序集合 ...

  4. Spring 多对对实体

    package com.wangshenghua.entity; import java.io.Serializable; import java.util.Set; import javax.per ...

  5. 【CodeForces】1172E. Nauuo and ODT

    题解 看了一遍题解(以及代码)但是没写代码-- 后来做梦的时候忽然梦到了这道题--意识到我需要补一下-- 这道题就是,对于每种颜色,把没有染成这种颜色的点标成黑点,然后计算每个联通块的平方 然后每个点 ...

  6. 关于 磁盘 I/O 的工作机制那些事

    总有一些你我看不见的东西,存在与你我周围 <深入分析 javaW 技术内幕> 读书感悟 作者 :淮左白衣 写于2018年4月11日19:35:06 写在前面的话 字节与字符的转换桥梁 用户 ...

  7. DRF图片路径问题的解决方法,网上爬取的图片放到ImageFiled自动带上域名

    由于博客园不支持markdown,推荐下面的url访问 原创url: https://blog.csdn.net/weixin_42495873/article/details/89440437 - ...

  8. pandas数据结构之Series笔记

    对Series的理解也源于对其相关的代码操作,本次仅贴一些代码来加深理解以及记忆 import pandas as pd import numpy as np s = pd.Series(np.ran ...

  9. java之理解面向对象

    1.程序设计的三种基本结构 顺序结构 顺序结构表示程序中的各操作是按照它们在源代码中的排列顺序依次执行的 选择结构 选择结构表示程序的处理需要根据某个特定的条件选择其中的一个分支执行.选择结构有单选择 ...

  10. Luogu4022 CTSC2012熟悉的文章(广义后缀自动机+二分答案+动态规划+单调队列)

    对作文库中的串建出广义SAM,然后显然可以二分答案,二分之后考虑暴力dp,设f[i]为前i位最长匹配长度,显然有f[i]=max(f[i-1],f[j]+i-j) (i-j>=l&&am ...