1.链表中环的入口节点数据结构
首先判断头指针是否是空的
而后须要判断这个链表中包不包含环:两个指针,一个一步一个两部,若是相遇,说明存在
而后判断环节点的个数:从相遇的位置开始,往前走并计数,直到和本身再次相遇,获得个数
而后找出入口节点:从头开始,俩指针一个先走n步,另外一个再走,两个相遇的位置就是入口节点位置dom
2.翻转链表oop
须要判断链表是否是空的或者链表是否是只有一个节点,若是是的话,直接就输出原来的链表了;spa
若是不是的话,翻转利用循环来作,由于须要将当前节点指向前一个节点,因此后一个节点须要先保存位置,也就是须要三个指针,一个pPre,一个pCur,一个pNext:先保存后一个节点,而后把当前节点指向前一个节点,而后把当前节点变成上一个节点,下一个节点变成当前节点;注意翻转以后头结点是原来的最后一个节点。指针
3.从尾到头打印链表code
思路(1):能够先翻转链表,再逐个输出blog
思路(2):这种具备“后进先出”特性的,用栈比较容易,建立一个栈存放链表的节点,存放完以后从栈顶依次取出便可ip
4.两个链表的第一个公共节点it
举例子:
1 2 5 9 6 3 0
7 8 9 6 3 0 io
首先须要知道的是,两个链表从公共节点开始,以后的节点确定都是如出一辙的;
能够先遍历获得两个链表各自的长度,而后让长的那个先走比另外一个长出的步数,再同时走,判断哪里相等哪里就是第一个公共节点了
5.链表中倒数第k个节点
单向链表确定是不能从后往前数的,这个跟上面有的相似,既然知道是倒数第k个,那就两个指针,让一个先走k-1步,而后两个同时走,判断先走的那个到尾结点了,那后走的那个就是倒数第k个节点。
6.删除链表中重复的节点
例如:1 2 3 3 4 4 5结果是1 2 5
首先须要判断头指针(第一个节点)和第二个节点是否是空的,若是是,返回头指针就好了;
正常状况的时候,由于有可能存在删除第一个节点的状况,因此须要先从新建立一个头指针ListNode* newHead = new ListNode(-1),而后把这个头指针赋初值指向本来的头指针newHead->next = pHead;
而后须要三个指针来解决这个问题,分别是pPre pCur pNext三个,pPre 赋初值newHead,pCur赋初值pHead, 利用当前节点的循环来进行:得判断当前节点和当前节点的下一个节点不为空才进入循环来查找和删除,由于里头要对节点进行删除,因此要先保存下一个节点,而后若是当前节点等于下一个节点的值,由于还要继续判断下一位,来一个循环,只要下一个节点和当前节点的值相等,就把pNext日后移一个,直到找到不相等的就退出这个查找的循环了;而后执行删除,也就是把上一个节点pPre的下一个节点变成pNext,当前操做循环的节点变成pNext,而后再去循环判断;
那若是当前节点和下一个节点的值不相等呢:指针日后挪,循环再判断,也就是pPre = pCur;pCur = pCur->next。
最后返回新的头结点newHead的下一个节点便可。
7.复制复杂的链表
分红三个步骤:
(1)复制原始链表的任意节点N并建立新节点N',把节点N'连接到节点N的后面
(2)设置复制出来的节点的random,假设原始链表上的N的random指向节点S,那么其对应复制出来的N'是N的next指向的节点,一样S'也是S的next指向的节点
(3)把整个链表根据奇数偶数分出两个链表来,偶数的就是拷贝的链表
/*struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};*/
classSolution {public:
RandomListNode* Clone(RandomListNode*pHead)
{if(pHead ==nullptr)returnnullptr;//分红三个步骤://1.复制原始链表的任意节点N并建立新节点N',把节点N'连接到节点N的后面//2.设置复制出来的节点的random,假设原始链表上的N的random指向节点S,那么其对应复制出来的N'是N的next指向//的节点,一样S'也是S的next指向的节点//3.把整个链表根据奇数偶数分出两个链表来,偶数的就是拷贝的链表
ClonedNode(pHead);
SetRandom(pHead);returnReconnectNodes(pHead);
}void ClonedNode(RandomListNode*pHead)
{
RandomListNode* pNode =pHead;while(pNode !=nullptr)
{
RandomListNode* newNode = new RandomListNode(0);//建立新节点
newNode->label = pNode->label;
newNode->next = pNode->next;
newNode->random =nullptr;
pNode->next =newNode;
pNode= newNode->next;
}
}void SetRandom(RandomListNode*pHead)
{
RandomListNode* pNode =pHead;while(pNode !=nullptr)
{
RandomListNode* pCloned = pNode->next;if(pNode->random != nullptr)//这一步判断别忘了,若是为空,会形成程序瘫痪
pCloned->random = pNode->random->next;elsepCloned->random =nullptr;
pNode= pCloned->next;//pNode日后移一位
}
}
RandomListNode* ReconnectNodes(RandomListNode*Head)
{
RandomListNode* pNode = Head;//循环操做
RandomListNode* pClonedHead =nullptr;
RandomListNode* pClonedNode = nullptr;//建立一个新节点,做为拷贝链表的头结点
if(pNode !=nullptr)
{
pClonedHead= pClonedNode = pNode->next;
pNode->next = pClonedNode->next;
pNode= pNode->next;
}while(pNode !=nullptr)
{
pClonedNode->next = pNode->next;
pClonedNode= pClonedNode->next;
pNode->next = pClonedNode->next;
pNode= pNode->next;
}returnpClonedHead;
}
};
8.翻转链表
给定一个链表,旋转链表,将链表每一个节点向右移动 k个位置,其中 k是非负数。
这个题说是翻转链表,其实就是改变了链表的头尾节点而已。
(1)先判断特殊状况,好比链表是否为空,是否只有一个元素,翻转的k是否为0等,不然直接返回
(2)而后处理通常状况,得先遍历一次获得链表的总长度size,而后将链表首尾相接,成为一个循环链表
(3)根据size和k的关系,计算出循环链表循环的次数loot= size - (k%size);
(4)而后进行指针循环,以前的头尾节点指针开始移动,次数为loop,直到移动结束,原先的尾结点指针指向的为新链表的尾部,原先的头结点指针指向的为新链表的头部。
9.扁平化多级双向链表
多级双向链表中,除了指向下一个节点和前一个节点指针以外,它还有一个子链表指针,可能指向单独的双向链表。这些子列表也可能会有一个或多个本身的子项,依此类推,生成多级数据结构,以下面的示例所示。
给你位于列表第一级的头节点,请你扁平化列表,使全部结点出如今单级双链表中。
这题太经典了!
/*// Definition for a Node.
class Node {
public:
int val;
Node* prev;
Node* next;
Node* child;
};*/
classSolution {public:
vectorv;//这题就是二叉树的前序遍历//能够先前序遍历,将全部节点放入容器中,而后再顺序进行先后链接
void dfs(Node*head)
{if(head ==nullptr)return;
v.push_back(head);
dfs(head->child);
dfs(head->next);
}
Node* flatten(Node*head) {
dfs(head);//这样就将全部的节点放入了容器中,按照前序的方式
int n = v.size();//获得容器中的节点数
for(int i=0;i
{if(i
v[i]->next = v[i+1];if(i>0)
v[i]->prev = v[i-1];
v[i]->child =nullptr;
}returnhead;
}
};
10.判断是否是回文链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };*/
classSolution {public:bool isPalindrome(ListNode*head) {//先判断特殊状况
if(head == nullptr || head->next ==nullptr)return true;//而后通常状况的判断方式是:先找到链表的中点,而后翻转后半部分,而后进行比较
ListNode* fast =head;
ListNode* slow =head;while(fast !=nullptr)
{
slow= slow->next;
fast= fast->next? fast->next->next : fast->next;
}//最后的slow为原来链表的中间节点,也是待会儿须要翻转链表的头结点//fast则指向了nullptr//而后须要进行翻转
ListNode* pPre =nullptr;while(slow !=nullptr)
{
ListNode* temp = slow->next;//存储下一个节点
slow->next =pPre;
pPre=slow;
slow=temp;
}//而后进行判断
while(pPre != nullptr && head !=nullptr)
{if(pPre->val != head->val)return false;
pPre= pPre->next;
head= head->next;
}return true;
}
};
tips:遇到链表为题时候的思考方式
(1)是否能用双指针解决
(2)知否能够将一个指针先走几步,再两个同时走解决
(3)是否须要知道链表节点的个数
(4)是否须要将链表变成循环链表处理
(5)考虑是否须要容器,容器能够放节点,容器的好处也是能知道链表的长度
(6)找链表的中点、翻转链表都是最基本的操做,在拔高的题目里头有可能会用到