链表数据结构刷题
leetcode206: Reverse Linked List 将链表反序
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//创建三个指针
ListNode *pre=NULL;
ListNode *curr=head;
if(head==NULL){
return head;
}
ListNode *Next=curr->next;
while(Next!=NULL){
ListNode *temp=Next->next;
curr->next=pre;
Next->next=curr;
pre=curr;
curr=Next;
Next=temp;
}
return curr;
}
};
时间复杂度为O(n);
leetcode83:Remove Duplicates from Sorted List 删除链表中的重复元素
ListNode* deleteDuplicates(ListNode* head) {
//时间复杂度为o(n) 空间复杂度为O(1)的算法的实现
ListNode *temp;
ListNode* returnhead=head;
if(head==NULL){
return NULL;
}
while(head->next!=NULL){
if(head->val == head->next->val){
temp=head->next;
head->next=head->next->next;
delete temp;
}
else{
head=head->next;}
}
return returnhead;
}
leetcode86:选取链表中的partion:将小于partion的值放在链表的开头,大于partion的值放在链表的后半部分
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//没有空间限制的代码 也就是不考虑空间复杂度的情况
ListNode *curr=head;
ListNode *less=new ListNode(-1);
ListNode *more=new ListNode(-1);
ListNode *l=less;
ListNode *m=more;
if(head==NULL||head->next==NULL){
return head;
}
while(curr!=NULL){
if(curr->val<x){
l->next=curr;
l=l->next;
}
else{
m->next=curr;
m=m->next;
}
curr=curr->next;
}
l->next=more->next;
m->next=NULL;
return less->next;
}
};
时间复杂度为O(n),空间复杂度为O(n)
算法改进:空间复杂度为O(1)的算法;需要注意边界条件,还是采用两个指针的方式;
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//考虑到空间复杂度的使用,使用O(1)的空间复杂度
//添加两个头结点
ListNode *first=new ListNode(0);
first->next=head;
ListNode *p=first;
ListNode *q=p->next;//设置好两个指针变量;
while(q!=NULL&&q->val<x){
p=p->next;
q=q->next;
}
while(q!=NULL){
ListNode *temp=q->next;
if(temp==NULL){
break;
}
if(temp->val>=x){
q=q->next;
}
else{
q->next=temp->next;
temp->next=p->next;
p->next=temp;
p=p->next;
}
}
return first->next;
}
};
leetcode 82,关于leetcode83的改进
/**
* 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* p=head->next;
// if(p->val!=head->val){
// head->next=deleteDuplicates(p);
// return head;
// }
// else{
// //找到第一个不相等的结点
// while(p&&p->val==head->val){
// p=p->next;
// }
// return deleteDuplicates(p);
// }
// }
//不使用递归的方式
//使用一个头结点的指针
if(head==NULL || head->next==NULL)
return head;
ListNode* node=new ListNode(-1);
node->next=head;
ListNode* re=node;
ListNode *curr=head;//用于遍历的指针
while(curr->next!=NULL){
if(curr->next->val!=curr->val){
if(node->next==curr)
node=curr;
else
node->next=curr->next;
}
curr=curr->next;
}
if(node->next!=curr)
node->next=curr->next;
return re->next;
}
};
leetcode86: 将链表进行排序,将小于x的链接结点放置在链表的前面,将大于x的链接结点放置在其后面;
使用两个指针来进行模拟,然后再将两个结点合并;
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//题目的意思 就是将相应的代码所有值小于相应值x的结点都放置到器前面,将所有的值大于x都放置到相应的后面
//通过两个链表 先分开,再合并
ListNode *list1=new ListNode(-1);
ListNode *list2=new ListNode(-1);
ListNode* head2=list2;
ListNode* head1=list1;
if(head==NULL||head->next==NULL){
return head;
}
while(head!=NULL){
if(head->val<x){
list1->next=head;
head=head->next;
list1=list1->next;
list1->next=NULL;
}
else{
list2->next=head;
head=head->next;
list2=list2->next;
list2->next=NULL;
}
}
list1->next=head2->next;
return head1->next;
}
};
链表加法:
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
//思路很简单将两个结点进行相加,然后将链表反转即可
if(l1==NULL){
return l2;
}
else if(l2==NULL){
return l1;
}
int cnt=0;
ListNode *ans=new ListNode(-1);
ListNode *head=ans;
while(l1!=NULL&&l2!=NULL){
int num=(l1->val+l2->val+cnt)%10;
cnt=(l1->val+l2->val+cnt)/10;
ListNode *temp=new ListNode(num);
ans->next=temp;
ans=ans->next;
l1=l1->next;
l2=l2->next;
}
if(l1!=NULL){
while(l1!=NULL){
int num=(l1->val+cnt)%10;
cnt=(l1->val+cnt)/10;
ListNode *temp=new ListNode(num);
ans->next=temp;
ans=ans->next;
l1=l1->next;
}
}
if(l2!=NULL){
while(l2!=NULL){
int num=(l2->val+cnt)%10;
cnt=(l2->val+cnt)/10;
ListNode *temp=new ListNode(num);
ans->next=temp;
ans=ans->next;
l2=l2->next;
}
}
if(cnt==1){
ans->next=new ListNode(1);
}
return head->next;
}
};
leetcode21:将两个有序链表进行merge,使其任然有序(通过递归的方式来构建,或者使用新的存储空间);
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
//将两个链表进行连接
//一种使用递归的方式
if(l1==NULL){
return l2;
}
if(l2==NULL){
return l1;
}
ListNode* head=new ListNode(-1);
ListNode* head2=head;
if(l1->val<l2->val){
head->next=l1;
head=head->next;
head->next=mergeTwoLists(l1->next,l2);
}
else{
head->next=l2;
head=head->next;
head->next=mergeTwoLists(l1,l2->next);
}
return head2->next;
}
leetcode23 合并多个链表的方式:比较难 需要采用的是优先队列来保存结点
leetcode24 Swap Nodes in Pairs 交换两个结点成对
多个指针穿针引线,注意边界条件等
ListNode* swapPairs(ListNode* head) {
if(head==NULL){
return NULL;
}
if(head->next==NULL){
return head;
}
ListNode* pre=new ListNode(-1);
ListNode* re=pre;
ListNode* curr=head;
// ListNode* Next=curr->next;
while(curr->next!=NULL){
ListNode* Next=curr->next;
ListNode* temp=Next->next;
pre->next=Next;
Next->next=curr;
curr->next=temp;
pre=curr;
curr=temp;
if(curr==NULL){
break;
}
}
return re->next;
}
leetcode148 对链表的排序(和数组中的排序的基本思想是一样的 但是在链表实现的时候归并排序可以是原址排序)
ListNode* sortList(ListNode* head) {
//使用链表的排序,使用mergesort采用的是的排序的方式 将在两个结点的中点开始切分
if(head==NULL){
return NULL;
}
if(head->next==NULL){
return head;
}
int size=get_list_size(head);
ListNode* mid=reach_mid(head,size/2-1);
ListNode* right=mid->next;
mid->next=NULL;
ListNode* l=sortList(head);
ListNode* r=sortList(right);
return merge(l,r);
}
int get_list_size(ListNode* head){
int i=0;
while(head!=NULL){
i++;
head=head->next;
}
return i;
}
ListNode* reach_mid(ListNode* head,int step){
for(int i=0;i<step;i++){
head=head->next;
}
return head;
}
ListNode* merge(ListNode* left,ListNode* right){
if(left==NULL){
return right;
}
if(right==NULL){
return left;
}
ListNode* head=new ListNode(-1);
ListNode* ans=head;
if(left->val<right->val){
head->next=left;
head=head->next;
head->next=merge(left->next,right);
}
else{
head->next=right;
head=head->next;
head->next=merge(left,right->next);
}
return ans->next;
}
leetcode160:
求两个链表的公共结点的方式:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
//只能说都好强啊, 通过走两轮来进行达到终点
ListNode *curr1=headA;
ListNode *curr2=headB;
while(curr1!=curr2){
curr1=curr1?curr1->next:headB;
curr2=curr2?curr2->next:headA;
}
return curr1;
}
leetcode328:将奇数和偶数的链表分离然后重新merge
ListNode* oddEvenList(ListNode* head) {
//肯定是使用两个指针的方式
//一个奇数指针,一个偶数指针
if(head==NULL||head->next==NULL){
return head;
}
ListNode* first=head;
ListNode* second=head->next;
ListNode* cur=second;
while(second!=NULL&&second->next!=NULL){
first->next=second->next;
first=first->next;
second->next=first->next;
second=second->next;
}
first->next=cur;
return head;
}
leetcode141:判断一个链表是否有环:
bool hasCycle(ListNode *head) {
//判断一个链表是否有环;
//太强大了,真是聪明啊通过快慢指针的方式来进行操作,一个指针走两步,一个指针走一步,看有没有相交
//凡是能走到终点就是false
if(head==NULL){
return false;
}
if(head->next==head){
return true;
}
if(head->next==NULL){
return false;
}
ListNode* fast=head->next;
ListNode* slow=head;
while(fast&&fast->next!=NULL){
if(slow==fast){
return true;
}
slow=slow->next;
fast=fast->next->next;
}
return false;
}
leetcode142:判断链表中环的入口:
思路:首先是判断链表是否有环,如果有环,得到环的长度(根据慢指针的步数来判断),然后再利用两个指针,第一个指针先走k步(k为链表中环的长度);代码如下:
ListNode *detectCycle(ListNode *head) {
//检测环的入口,首先要判断是否有环;
if(hashCircle(head)){
//首先得到环的长度,走了多少步相交 就是多少长度的环
ListNode* fast=head->next;
ListNode* slow=head;
int cnt=0;
while(fast!=slow){
fast=fast->next->next;
slow=slow->next;
cnt++;
}
ListNode* first=head;
ListNode* second=head;
for(int i=0;i<cnt+1;i++){
first=first->next;
}
//然后让first指针首先前进cnt+1步,然后再和后指针 一步一步的前进直到相交(画图分析一下就行)
while(first!=second){
first=first->next;
second=second->next;
}
return first;
}
else{
return NULL;
}
}
bool hashCircle(ListNode* head){
if(head==NULL){
return false;
}
if(head->next==NULL){
return false;
}
ListNode* slow=head;
ListNode* fast=head->next;
while(fast!=NULL&&fast->next!=NULL){
if(slow==fast){
return true;
}
else{
slow=slow->next;
fast=fast->next->next;
}
}
return false;
}