目录
-
从尾到头打印链表(剑指欧肥儿)
题目描述:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
解题代码:
class Solution{
public:
vector<int> printListFromTailToHead(ListNode* head){
vector<int> result;
stack<int> help;
ListNode* p = head;
while(p != NULL){ //NULL不能写成null
help.push(p -> val); //记住链表节点的值表示方法 p->val
p = p -> next;
}
while(!help.empty()){
result.push_back(help.top());
help.pop()
}
return result
}
}
代码思路:
- 引入辅助栈
- 代码时间复杂度为O(n)
栈的长度大小,为len = help.size()
-
删除链表中重复的节点(剑指欧肥儿)
题目描述:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
解题代码:
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead == NULL || pHead->next == NULL) return pHead;
ListNode* current;
if(pHead->val == pHead->next->val){
current = pHead->next;
while(current != NULL && current->val == pHead->val){
current = current->next;
}
return deleteDuplication(current);
}else{
pHead->next = deleteDuplication(pHead->next);
return pHead;
}
}
};
代码思路:
- 运用递归(这个递归烧脑啊)
- 每个if,else都要return,否则会报错
- while(current != NULL && current->val == pHead->val)不能写成whiel(current != NULL && current->val == current->next->val) 会堆栈溢出
- 递归出当前节点的下一个节点直至到NULL节点
题外话:数组在作为函数参数时就会退化为指针。
-
链表中环的入口结点(剑指欧肥儿)
题目描述:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题代码:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
//变量
ListNode* pFast,*pSlow;
ListNode* tempNode;
ListNode *p1,*p2;
pFast = pHead->next;
pSlow = pHead;
int count = 1;
//排除不可能
if(pHead == NULL || pHead->next == NULL || pHead->next->next ==NULL) return NULL;
//首先找到环中的一个节点
while(pFast != NULL && pSlow != NULL && pFast!=pSlow){
pFast = pFast->next;
pSlow = pSlow->next;
if(pFast == NULL){
return NULL;
}else{
pFast = pFast->next;
}
}
//计算出环中的节点个数n
tempNode = pFast->next;
while(tempNode != pFast){
tempNode = tempNode->next;
++count;
}
//快指针比满指针多n步,每次一起走一步
p1 = pHead;
p2 = pHead;
for(int i=0;i<count;i++){
p1 = p1->next;
}
while(p1 != p2){
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
};
代码思路(这道题思路非常重要):
- 排除特殊情况
- 利用两个快慢指针找出一个在环中的节点
- 步骤2得到的环中节点,来得出环的个数n
- 再利用两个快慢指针,设置两个指针步长差距为n,每次同时走一步,当两个指针相遇时,指针对应的节点就是环的起点。
-
两个链表的第一个公共结点(剑指欧肥儿)
题目描述:输入两个链表,找出它们的第一个公共结点。
解题代码一:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode* p1 = pHead1;
ListNode* p2 = pHead2;
int len1 = 0, len2 = 0;
int diff;
while(p1){
p1 = p1 -> next;
len1++; //得出pHead1链表包括头结点的节点数n
}
while(p2){
p2 = p2 -> next;
len2++;
}
if(len1>len2){
diff = len1 - len2;
p1 = pHead1;
p2 = pHead2;
}else{
diff = len2 - len1;
p1 = pHead2;
p2 = pHead1;
}
for(int i = 0; i < diff; i++){
p1 = p1 -> next;
}
while((p1!=NULL) && (p2!=NULL)){
if(p1 == p2) break;
p1 = p1 -> next;
p2 = p2 -> next;
}
return p1;
}
};
解题思路:
- 首先关键在于,如果两个链表相交,那么他们相交以后的链表,就是同一个链表了。
- 所以,我们先把两个链表的长度算出来,分别为len1,len2。
- 判断len1和len2谁长,并计算出len1-len2的差值diff
- 然后p1指向长的链表,并前进diff个节点,这样p1剩余的节点数就和p2一样了。
- 然后p1和p2共同往前走,每走一步比较他们是否是相等。不相等则继续比较。直到p1返回NULL或相同的节点为止。
解题代码二:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode* p1 = pHead1;
ListNode* p2 = pHead2;
while(p1 != p2){
p1 = (p1 == NULL) ? pHead2 : p1 -> next;
p2 = (p2 == NULL) ? pHead1 : p2 -> next;
}
return p1;
}
};
解题思路:
- 这个方法很NB是真的很NB,不需要过多的计算两个链表的长度,长度之差,直接让指针一直往下走就OK了,但是这个方法很难想到。
- 指向长链表的指针走到空值的时候,指针指向了另一个短链表的头部,此时两个指针是距离链表的尾部是相等距离的。
- 记下这个方法,很经典!
-
合并两个排序的链表(剑指欧肥儿)
题目描述:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
解题代码:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if(!pHead1){
return pHead2;
}
if(!pHead2){
return pHead1;
}
ListNode* p;
ListNode* pHead;
if(pHead1->val <= pHead2->val){
pHead = pHead1;
pHead1 = pHead1 -> next;
}else{
pHead = pHead2;
pHead2 = pHead2 -> next;
}
p = pHead; //给p初始化。p会接在pHead后面把
while(pHead1 && pHead2){
if(pHead1 -> val <= pHead2 -> val){
p -> next = pHead1;
pHead1 = pHead1 -> next;
p = p -> next;
}else{
p -> next = pHead2;
pHead2 = pHead2 -> next;
p = p -> next;
}
}
if(pHead1){
p -> next = pHead1;
}
if(pHead2){
p -> next = pHead2;
}
return pHead;
}
};
解题思路:
- 最关键的一点,判断输入两个链表是否为NULL,如果不判断,测试用例是绝对过不了的。
- 本题采用外排法,对两个链表进行遍历比较。
- p = pHead;将pHead的节点赋值给p节点,然后p节点帮助pHead连接后面的节点。
- 最后,有一个链表还有多余的尾巴,即把多余的尾巴加在p后面。
-
反转链表(剑指欧肥儿)
题目描述:输入一个链表,反转链表后,输出新链表的表头。
解题代码:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead == NULL || pHead -> next == NULL) return pHead;
while(pHead){
s.push(pHead);
pHead = pHead -> next;
}
ListNode* Head;
while(!s.empty()){
if(!pHead){
pHead = s.top();
s.pop();
Head = pHead;
}else{
pHead->next = s.top();
s.pop();
pHead = pHead -> next;
}
}
pHead -> next = NULL; //这一句不加的话,测试用例100%过不了。
return Head;
}
private:
stack<ListNode*> s;
};
解题思路:
- 用栈将节点保存,然后输出,即是逆序节点。
- 逆序输出后,最后一个节点一定要显示赋值为NULL——pHead -> next = NULL;