leetcode 链表所有题目
来源:互联网 发布:api原油库存数据预测 编辑:程序博客网 时间:2024/05/21 06:33
简单题目
141 判断一个链表是否有环 使用快慢指针
class Solution { public: bool hasCycle(ListNode *head) { ListNode* pFast=head; ListNode* pSlow=head; if(head==NULL) return false; while(pFast!=NULL) { pSlow=pSlow->next; pFast=pFast->next; if(pFast==NULL) return false; pFast=pFast->next; if(pFast==NULL) return false; if(pFast==pSlow) return true; } } };
237 删除链表中的指定节点
给定链表中的一个节点,将这个节点删除。单链表的特点是:不能找到前驱结点,本题的方法是,将下一个节点的值复制到当前节点,然后跳过下一个节点。
class Solution { public: void deleteNode(ListNode* node) { if (node==NULL) return; else { node->val=node->next->val; node->next=node->next->next; } } };
83.在排序链表中删除重复的节点
1->1->2
, return 1->2
.Given
1->1->2->3->3
, return 1->2->3
.方法1:使用一个循环,循环判断cur->next,之前需要判断head是否为空
class Solution { public: ListNode* deleteDuplicates(ListNode* head) { ListNode* cur=head; if(head==NULL) return head; while(cur->next) { if(cur->next->val==cur->val) cur->next=cur->next->next; else cur=cur->next; } return head; } };方法2:循环判断当前节点
class Solution { public: ListNode* deleteDuplicates(ListNode* head) { ListNode* cur=head; while(cur) { while(cur->next&&cur->next->val==cur->val) cur->next=cur->next->next; cur=cur->next; } return head; } };方法3:递归版本
class Solution { public: ListNode* deleteDuplicates(ListNode* head) { if(head==NULL||head->next==NULL) return head; head->next=deleteDuplicates(head->next); return head->val==head->next->val?head->next:head; } };
160. Intersection of Two Linked Lists 找到两个链表的公共节点
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
方法1:先求两个链表的长度,然后让唱的指针先走掉长出的部分,最后两个链表一起走指针。时间复杂度为O(m+n),空间复杂度是1。
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { if(headA==NULL||headB==NULL) return NULL; unsigned int lengthA=getLength(headA); unsigned int lengthB=getLength(headB); ListNode *pA=headA,*pB=headB; if(lengthA<lengthB) { int clap=lengthB-lengthA; while(clap!=0){ headB=headB->next; clap--;} } else { int clap=lengthA-lengthB; while(clap!=0){ headA=headA->next; clap--;} } while(headA!=headB&&headA!=NULL&&headB!=NULL) { headA=headA->next; headB=headB->next; } return headA; } unsigned int getLength(ListNode* pcurrent)//长度计算函数 { ListNode* p=pcurrent; unsigned int length=0; while(p!=nullptr) { ++length; p=p->next; } return length; } };
206 翻转链表
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */class Solution {public: ListNode* reverseList(ListNode* head) {
//注意处理开头部分和特殊情况 if(head==NULL||head->next==NULL) return head; ListNode* pNext=head->next; if(pNext->next==NULL) { pNext->next=head; head->next=NULL; return pNext; } ListNode* pNextNext=pNext->next; head->next=NULL; pNext->next=head; while(pNextNext!=NULL) { ListNode* pTemp=pNextNext->next; pNextNext->next=pNext; pNext=pNextNext; pNextNext=pTemp; } return pNext; }};
class Solution {public: ListNode* reverseList(ListNode* head) { //使用pre零头结点和cur原来的头结点处理链表,这个程序全程pre和cur都没有变,变的是他们指向的子节点 ListNode* pre=new ListNode(0);//新建零表头 pre->next=head; ListNode* cur=head; while(cur&&cur->next) { ListNode* temp=pre->next;//用一个指针存储需要被指向的父节点 pre->next=cur->next;//pre指向原来的子节点 cur->next=cur->next->next;//cur指向子节点的下一个节点,可能是空的 pre->next->next=temp;//将子节点的下一个节点指向存储好的父节点位置temp,这里不能指向cur,因为cur保存的永远是原来的第一个头结点 } //当cur头指向的下一个子节点是空节点时 return pre->next; }};
方法3:使用三个指针,循环操作,pre是当前节点的前一个节点,如果当前节点时头结点,pre预设为NULL,head是当前节点,next是head的下一个节点
class Solution {public: ListNode* reverseList(ListNode* head) { ListNode* pre=NULL; while(head){ ListNode* next=head->next; head->next=pre; pre=head; head=next; } return pre; }};方法4:使用递归,找到最后一个节点,每层递归都是把当前节点的子节点的next指向当前节点,当前节点指向空,不会存在丢失现象,因为递归的层次保留了节点的指向信息。注意书写递归函数的返回位置和返回值是很很重要的。
class Solution {public: ListNode* reverseList(ListNode* head) { if(head==NULL||head->next==NULL) return head;//考虑head是空的情况,这句目的是找到最后一个节点 ListNode* cur=reverseList(head->next); //递归的根节点时,cur得到的是当前head的子节点 head->next->next=head; head->next=NULL; return cur;//cur保存最后的尾节点 }};
234 Palindrome Linked List 回文链表
class Solution {public: bool isPalindrome(ListNode* head) { //自己想的方法,使用递归的形式,参照206中的递归方法 ListNode* pCur=head; return comP(head,pCur,0); } bool comP(ListNode* head,ListNode* pCur,int count){ if(pCur==NULL||pCur->next==NULL) { length=count; return true; } count++; bool tempdecide=comP(head,pCur->next,count); if(tempdecide==false) return false; count--; if(count*2<length) return tempdecide; if(head->val==pCur->next->val){ head=head->next; return true; } else return false; } private: int length; };方法1:
class Solution {public: bool isPalindrome(ListNode* head) { if(head==NULL||head->next==NULL) return true; ListNode* slow=head; ListNode* fast=head; //让快指针运动到最后,这时如果是偶数个,慢指针指向中间偏左的节点,如果是奇数个,慢指针指向中间的节点 while(fast->next&&fast->next->next) { slow=slow->next; fast=fast->next->next; } slow->next=reverseList(slow->next); slow=slow->next; while(slow){ if(slow->val!=head->val) return false; slow=slow->next; head=head->next; } return true; } //翻转链表,使用206第三种方法 ListNode* reverseList(ListNode* head){ ListNode* pre=NULL; ListNode* next=NULL; while(head){ next=head->next; head->next=pre; pre=head; head=next; } return pre; }};
class Solution {public: ListNode* temp; bool isPalindrome(ListNode* head) { if(head==NULL) return true; temp=head; return check(head); } bool check(ListNode* head){ if(head==NULL) return true; bool tempcheck=check(head->next)&(temp->val==head->val); temp=temp->next; return tempcheck; }};
21 合并两个排序链表 merge two linked list
class Solution {public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if(l1==NULL) return l2; if(l2==NULL) return l1; ListNode* prehead=new ListNode(0); if(l1->val<l2->val) { prehead->next=l1; l1=l1->next; } else { prehead->next=l2; l2=l2->next; } ListNode* temp=prehead->next; while(l1&&l2){ if(l1->val<l2->val) { temp->next=l1; l1=l1->next; } else { temp->next=l2; l2=l2->next; } temp=temp->next; } if(l1==NULL) temp->next=l2; else temp->next=l1; return prehead->next; }};
方法2:递归方法
class Solution {public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if(l1==NULL) return l2; if(l2==NULL) return l1; if(l1->val<l2->val) { l1->next=mergeTwoLists(l1->next,l2); return l1; } else { l2->next=mergeTwoLists(l2->next,l1); return l2; } }};方法3:
方法1的改进版本。
class Solution {public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode* prehead=new ListNode(0); ListNode* head=prehead; while(l1&&l2){ if(l1->val<l2->val) { prehead->next=l1; l1=l1->next; } else { prehead->next=l2; l2=l2->next; } prehead=prehead->next; } prehead->next=l1?l1:l2; return head->next; }};
中等难度
61 Rotate List
描述:给定一个链表,在链表的倒数第k个位置旋转链表
Given 1->2->3->4->5->NULL
and k = 2
,
return 4->5->1->2->3->NULL
.
方法:先让一个指针移动k-1步,然后和另外一个头指针一起移动,当最前面的指针移动到末尾时,后面的指针正好移动到旋转位置;
注意要保存后一个指针的前一个指针,还要保存头指针。
class Solution {public: ListNode* rotateRight(ListNode* head, int k) { if(head==NULL||k<=0) return head; ListNode* frontNode=head; //如果k的值大于链表长度怎么办? --k; while(k&&frontNode!=NULL) { frontNode=frontNode->next; k--; } if(frontNode==NULL) return head; ListNode* backNode=head; ListNode* tempNode=head; while(frontNode->next){ frontNode=frontNode->next; tempNode=backNode; backNode=backNode->next; } if(backNode==head) return head; frontNode->next=head; tempNode->next=NULL; return backNode; }};方法1: 首先遍历一边求出总的长度,并把链表编程环,然后根据整除数对链表做操作
class Solution {public: ListNode* rotateRight(ListNode* head, int k) { if(!head) return NULL; int length=1; ListNode* tail=head; while(tail->next){ tail=tail->next; length++; } tail->next=head;//变成环状链表 if(k%=length)//对移动k数取余数 { for(auto i=0;i<length-k;i++) tail=tail->next;//让tail从尾节点移动到旋转节点的前一个节点 } ListNode* newHead=tail->next; tail->next=NULL; return newHead; }};
143 recorder List
Given a singly linked list L: L0?L1?…?Ln-1?Ln,
reorder it to: L0?Ln?L1?Ln-1?L2?Ln-2?…
You must do this in-place without altering the nodes' values.
For example,
Given {1,2,3,4}
, reorder it to {1,4,2,3}
.
交叉更改链表顺序,但是不能直接改变数值
我的思路:使用快慢指针,将后半段链表翻转,使用前面回文串的思路,然后与第一个链表交叉起来。
这个思路与标准思路一致
class Solution {public: void reorderList(ListNode* head) { if(head==NULL) return ; ListNode* fast=head; ListNode* slow=head; while(fast->next&&fast->next->next){//注意判断条件,需要后面两个子节点都判断 fast=fast->next->next; slow=slow->next; } //操作slow指针后面的链表,将其翻转 slow->next=reverseNode(slow->next); //将链表截断,slow指向空,然后新的slow指向后面的翻转链表 ListNode* tail=slow; slow=slow->next; tail->next=NULL; //下面将两个链表合并到一起,注意末尾操作的特殊性 ListNode* newHead=head; while(slow)//注意判断条件决定最后末尾的操作,head的长度可能比slow多一位 { ListNode* next1=head->next; ListNode* next2=slow->next; head->next=slow; slow->next=next1; slow=next2; head=next1; } return ; } //翻转链表的函数 ListNode* reverseNode(ListNode* head){ //使用pre、head、next三个指针 ListNode* pre=NULL; ListNode* next=NULL; while(head)//注意这里的判断条件,决定末尾的情况。一定不能出现空指针next操作 { next=head->next; head->next=pre; pre=head; head=next; } return pre; }};
142Linked List Cycle II 环状链表2
class Solution {public: ListNode *detectCycle(ListNode *head) { if(head==NULL) return head; ListNode* fast=head; ListNode* last=head; while(fast->next&&fast->next->next)//注意需要先判断fast->next,因为必须满足这一点才能继续往下判断 { last=last->next; fast=fast->next->next; if(last==fast) break; } if(fast->next==NULL||fast->next->next==NULL) return NULL; while(true){ if(head==last) break; head=head->next; last=last->next; } return head; }};
138Copy List with Random Pointer26.3%Medium
class Solution {public: RandomListNode *copyRandomList(RandomListNode *head) { if(head==NULL) return NULL; RandomListNode* headCopy=head;//复制原来的头结点 //第一步,在每个节点后面复制一个相同数值的节点 while(head){ RandomListNode* newNode=new RandomListNode(head->label); RandomListNode* next=head->next; head->next=newNode; newNode->next=next; head=next; } //第二步,处理随机指针,将每个新节点的random指针指向,它前面节点random指针指向的下一个节点 RandomListNode* newHead=headCopy->next; RandomListNode* headCopyCopy=headCopy; while(headCopy){ newHead->random=headCopy->random?headCopy->random->next:NULL;//注意random不一定指向一个节点,有可能是空值 headCopy=headCopy->next->next; if(headCopy==NULL) break; newHead=newHead->next->next;//当到达尾部时,newHead处于结尾,这个语句将产生错误,所以需要在前面退出程序 } //第三步,分解现在的链表 headCopy=headCopyCopy; newHead=headCopy->next; while(headCopy&&headCopy->next&&headCopy->next->next){ RandomListNode* middle=headCopy->next; RandomListNode* last=middle->next; headCopy->next=last; headCopy=middle; } headCopy->next=NULL; return newHead; }};
https://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba?tpId=13&tqId=11178&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 这是牛客网上自己写的另外一个版本
92Reverse Linked List II 倒置链表 2
Given 1->2->3->4->5->NULL
, m = 2 and n = 4,
return 1->4->3->2->5->NULL
.
Note:
Given m, n satisfy the following condition:
1 ≤ m ≤ n ≤ length of list.
自己的思路:与前面的206没有太大的区别,需要注意的几点是:
(1)应该设置表头指针,这样能处理第一个节点就参与旋转的情况;
(2)注意要设置多个指针保存中间段的入口和出口一共四个节点;
(3)m和n相等的情况是特殊的,在程序开始时直接处理。
class Solution {public: ListNode* reverseBetween(ListNode* head, int m, int n) { if(head==NULL||m==n) return head; ListNode* preHead=new ListNode(-1);//表头指针 ListNode* result=preHead; preHead->next=head;//表头指针指向原来的头结点,这能解决开始头结点就需要旋转的情况 ListNode* frontEntry=NULL;//保存入口之前的节点 //需要表头指针 for(int i=0;i<m;i++) { frontEntry=preHead; preHead=preHead->next; } //下面旋转节点,采用三节点法,三个指针依次是preNode、preHead、next ListNode* preNode=NULL; ListNode* frontNode=preHead;//保存入口节点 for(int i=0;i<n-m+1;i++){ ListNode* next=preHead->next; preHead->next=preNode; preNode=preHead;//注意 preHead=next;//注意这两行的顺序 } //此时preNode指向出口节点,preHead指向出口节点的下一个节点 frontEntry->next=preNode;//原来的入口指向中间新的头部 frontNode->next=preHead;//中间新段的尾部指向后来剩余的头部 return result->next; }};
19Remove Nth Node From End of List33.3%Medium
将一个链表的倒数第n个节点去除,返回链表的头结点
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
主要的难点是删除的点是第一个时怎么操作,采取的办法是认为的定义一个头结点指向原来的头结点。
方法1,代码如下:
class Solution {public: ListNode* removeNthFromEnd(ListNode* head, int n) { //如果移除的是第一个节点,呵呵 //考虑这种特殊的情况,需要定义一个头结点指向原来的头结点,这样就能解决删除第一个节点的情况了 ListNode* newHead=new ListNode(0); newHead->next=head; ListNode * fast =newHead,* slow=newHead; for(int i=0;i<n;i++) fast=fast->next; while(fast->next) { slow=slow->next; fast=fast->next; } ListNode* toBeDelete=slow->next; slow->next=slow->next->next; delete toBeDelete; return newHead->next; }};
2 Add Two Numbers 27.6%Medium
描述:两个链表存储每一位数,求加和的新链表
要求:争取一次遍历成功
自己的代码:有错崩溃
class Solution {public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { //注意两个链表的长度可能不一样长 int addNumber=0; ListNode* cl1=l1,* cl2=l2,* tempNode=l1; while(cl1&&cl2) { int temp=cl1->val+cl2->val+addNumber; if(temp>9){ addNumber=1; cl1->val=temp-10; } else{ addNumber=0; cl1->val=temp; } tempNode=cl1; cl1=cl1->next; cl2=cl2->next; } if(cl1==NULL&&cl2!=NULL) { tempNode->next=cl2; } while(tempNode) { int temp=tempNode->val+addNumber;//有错 if(temp>9){ addNumber=1; tempNode->val=temp-10; } else{ addNumber=0; tempNode->val=temp; } cl1=tempNode; tempNode=tempNode->next; } if(addNumber==1) { ListNode* temp=new ListNode(1); cl1->next=temp; } return l1; }};
方法:新建一个链表,在循环中单独判断两个链表是否为空,使用sum保存每次的加和,并在链表中保存余数,在下一次循环中,这个sum值的起始值是除10后的数。
class Solution {public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode *c1=l1; ListNode *c2=l2; ListNode * result=new ListNode(0); ListNode* tempNode=result; int sum=0; while(c1||c2) { sum/=10; if(c1) { sum+=c1->val; c1=c1->next; } if(c2){ sum+=c2->val; c2=c2->next; } tempNode->next=new ListNode(sum%10); tempNode=tempNode->next; } if(sum>9) { tempNode->next=new ListNode(1); } return result->next; }};
另外一种方法:使用条件运算符简化代码
class Solution {public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode* p=new ListNode(0); ListNode * temp=p; int extra=0; while(l1||l2||extra){ int sum=extra+(l1?l1->val:0)+(l2?l2->val:0); extra=sum/10; temp->next=new ListNode(sum%10); temp=temp->next; l1=l1?l1->next:l1; l2=l2?l2->next:l2; } return p->next; }};445Add Two Numbers II46.1%Medium
描述:这个题目是增进版本,高位数在前面,低位数在后面Example:
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)Output: 7 -> 8 -> 0 -> 724Swap Nodes in Pairs38.2%Medium
给定一个链表,交换两个相邻的节点
只能使用常数空间,不能更改节点的值Given1->2->3->4
, you should return the list as2->1->4->3
.思路:因为第一个节点会变,所以设置表头指针。由于奇偶性不同,一次循环需要处理两个节点。如果是奇数个,最后一个节点不动。自己写的代码: 题目比较简单,主要是考虑每次循环如何处理(要做三次指针操作,并且保存下一次循环的指针p)class Solution {public: ListNode* swapPairs(ListNode* head) { if(head==NULL) return head; ListNode* preHead=new ListNode(0); preHead->next=head; ListNode* p=preHead; while(p->next&&p->next->next){ ListNode* next=p->next; ListNode* nextNext=next->next; ListNode* third=nextNext->next; p->next=nextNext; nextNext->next=next; next->next=third; p=next; } return preHead->next; }};86Partition List 32.5%Medium 类似快速排序
给定一个数,将链表重新排序Given1->4->3->2->5->2
and x = 3,
return1->2->2->4->3->5
.自己的思路:设置两个指针,分别指向小于指定数和大于指定数。当遍历完成之后,合并两个链表。小链表要保存头部作为所有的头,大链表也要保存头部与小链表的尾部相连,大链表的为节点需要指向NULL。如果所有的值都小于这个数,和所有值都大于这个数,程序也可以正常执行class Solution {public: ListNode* partition(ListNode* head, int x) { if(head==NULL) return head; ListNode* small=new ListNode(-1); ListNode* big=new ListNode(-1); ListNode* smallCopy=small; ListNode* bigCopy=big; while(head){ if(head->val<x){ smallCopy->next=head; smallCopy=head; } else { bigCopy->next=head; bigCopy=head; } head=head->next; } bigCopy->next=NULL; smallCopy->next=big->next; delete big; delete small; return small->next; }};别人的思路基本一致。82Remove Duplicates from Sorted List II29.4%Medium
给定一个排序链表,去除链表中所有重复的数,注意重复的数字全部去除。与版本I不同,版本1是留下一个重复的数字。自己的思路:设置起始头结点,它所指向的数必须和后面的数不同。编不下去喽看别人的思路:使用递归放一放吧328Odd Even Linked List 43.4%Medium
将一个链表原来处在奇数位置的节点放到前面,偶数位置的节点放到后面Example:
Given1->2->3->4->5->NULL
,
return1->3->5->2->4->NULL
.自己的思路:与86题思路类似,设置两个表头指针odd和even,分别指向奇数和偶数节点,完成后将奇数节点的尾节点指向偶数的头结点。class Solution {public: ListNode* oddEvenList(ListNode* head) { ListNode* preOdd=new ListNode(-1); ListNode* preEven=new ListNode(-1); ListNode* odd=preOdd; ListNode* even=preEven; bool oddOrEven=true;//奇数为true,偶数为false while(head){ if(oddOrEven){ odd->next=head; odd=head; oddOrEven=false; } else{ even->next=head; even=head; oddOrEven=true; } head=head->next; } even->next=NULL; odd->next=preEven->next; return preOdd->next; }};109Convert Sorted List to Binary Search Tree 33.8%Medium
148 sort list
将一个链表排序,要求时间复杂度是O(n log n),空间复杂度是1.使用归并排序147 insertion sort list使用直接插入排序将一个链表排序。25. Reverse Nodes in k-Group
自己写的代码:class Solution {public: ListNode* reverseKGroup(ListNode* head, int k) { ListNode* last=head; ListNode*newHead=new ListNode(0); newHead->next=head; ListNode* first=newHead; int n=1; while(last) { if(n==k) {//如果收集到了k个节点 ListNode* pre=last->next; ListNode* temp=first->next; ListNode* nowHead=first->next; while(n) { ListNode* next=nowHead->next; nowHead->next=pre; pre=nowHead; nowHead=next; n--; } n=1; first->next=pre; first=temp; last=first->next; continue; } last=last->next; n++; } n--; return newHead->next; } };
- leetcode 链表所有题目
- LeetCode所有题目的代码
- leetcode 数组类 所有题目
- leetcode链表题目总结
- 【leetcode】链表常见题目总结
- leetcode题目 反转链表系列问题
- 【LeetCode题目记录-12】所有合法的括号序列
- 【LeetCode-面试算法经典-Java实现】【所有题目目录索引】
- LeetCode-Easy部分中标签为HashTable的所有题目
- LeetCode-Easy部分中标签为LinkedList的所有题目
- LeetCode-Easy部分中标签为Math的所有题目
- LeetCode-Easy部分中标签为String的所有题目
- 【LeetCode-面试算法经典-Java实现】【所有题目目录索引】
- leetcode题目 合并N个排序好的链表
- 判断链表是否有环---leetcode题目
- Leetcode链表部分题目常用方法技巧总结
- leetcode题目
- LeetCode 题目
- hihocoder 1109 : 最小生成树三·堆优化的Prim算法
- Python 介绍及基本语法
- 关于梯度下降优化算法momentum的一些疑
- 线段树基本入门知识
- java的两种动态代理
- leetcode 链表所有题目
- 《机器学习实战》学习笔记-[6]-支持向量机SMO
- JAVA——JVM
- udev
- SEO(搜索引擎优化)友情链接策略
- pl/sql监听配置
- Python_2
- 关于spring动态切换数据源
- C/C++结构体总结