【力扣】C/C++单链表、双指针技巧(环形链表、相交链表、删除链表元素)、反转链表

C语言

创建链表

在这里插入图片描述

插入节点

在这里插入图片描述

删除结点

在这里插入图片描述
在这里插入图片描述

销毁链表(free)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数组模拟单链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

归并排序

在这里插入图片描述
在这里插入图片描述
数组实现

快慢指针

在这里插入图片描述
len>>1

二进制数右移1,相当于除以2

快指针:一次两个结点
慢指针:一次一个结点

在这里插入图片描述

c++

单链表

#include<iostream>
using namespace std;

typedef struct SinglyListNode{
	int val;
	SinglyListNode *next = NULL;
};
static int size=0;

class MyLinkedList {
	public:
	    int get(int index);//找下标为index的结点,下标为 0-index 
		void addAtHead(int val);//在头添加结点 
	    void addAtTail(int val);//在尾添加结点 
	    void addAtIndex(int index, int val);//在index前添加结点 
	    void deleteAtIndex(int index);//删除第index结点 
	    void coutLinkedList();//打印链表 
	private:
//head为地址 
    	SinglyListNode* head=NULL;
};

void MyLinkedList::addAtHead(int val) {
//输入新结点cur 
	SinglyListNode *cur = new SinglyListNode();
	cur->val=val;
	cur->next=head;
//指定cur为新head 
	head=cur;
	size++;
}

void MyLinkedList::addAtTail(int val){
	if(size==0){
		addAtHead(val);
		return;
	}
	SinglyListNode *pLastNode = head;
	SinglyListNode LastNode =*pLastNode;
	for(int i=0;i<size-1;i++){
		pLastNode=pLastNode->next;
	}
	SinglyListNode *newNode=new SinglyListNode();
	newNode->val=val;
	newNode->next=NULL;
	pLastNode->next=newNode;
	size++;
}

void MyLinkedList::addAtIndex(int index, int val){
	if(index<=0){
		addAtHead(val);
		return;
	}
	if(index==size){
		addAtTail(val);
		return;
	}
	if(index>size) return ;
	SinglyListNode *SerNode=head;//0 1 2 a 3 4 5  3
//SerNode为index结点的地址,在这个结点前插入一个新的结点 
	for(int i=1;i<index;i++){
		SerNode=SerNode->next;
	}
//创建新的结点 
	SinglyListNode *newNode = new SinglyListNode();
	newNode->val=val;
	newNode->next=SerNode->next;//新结点的指针指向原链表后一个结点 
//SerNode的next指向新结点	
	SerNode->next=newNode;
	size++;
}

void MyLinkedList::deleteAtIndex(int index){
	if(index<0||index>=size) return; 
	
	SinglyListNode *PrevNode=head;
	SinglyListNode *NextNode;
	SinglyListNode *MidNode;
	if(index==0){
		size--;
		head=head->next;
		delete PrevNode;
		return;
	}
	if(index==size-1){
		for(int i=1;i<size;i++){
			PrevNode=PrevNode->next;
		}
		NextNode=PrevNode->next;
		PrevNode->next=NULL;
		delete NextNode;
		size--;
		return;
	}
	for(int i=1;i<index;i++){
		PrevNode=PrevNode->next;
	}
	MidNode=PrevNode->next;
	NextNode=MidNode->next;
	PrevNode->next=NextNode;
	delete MidNode;
	size--;
	return;
}

int MyLinkedList::get(int index){
	if(index>=size||index<0||size==0) return -1;
	SinglyListNode *SerNode=head;
	for(int i=0;i<index;i++){
		SerNode=SerNode->next;
	}
	cout<<SerNode->val<<endl;
	return SerNode->val;
}
void MyLinkedList::coutLinkedList(){
	SinglyListNode *a =head;
	for(int i=0;i<size;i++){
		cout<<a->val<<" ";
		if(a->next==NULL) break;
		a=a->next;
	}
	cout<<endl;
}
int main()
{
	MyLinkedList linkedList;
	linkedList.addAtHead(3);
	linkedList.addAtTail(8); 
	linkedList.addAtIndex(1,5);
	linkedList.coutLinkedList();
	linkedList.get(0);
	linkedList.deleteAtIndex(2);
	linkedList.coutLinkedList();
	return 0;
}

运行结果:
在这里插入图片描述

双指针技巧

环形链表Ⅰ

在这里插入图片描述

快慢指针最终会相遇

/**
 * 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) {
        if(head==NULL) return false;
        ListNode *slow =head;
        ListNode *fast =head;
        do{
            if(slow->next!=NULL) slow=slow->next;
            else return false;            
            if(fast->next!=NULL) fast=fast->next;
            else return false;
            if(fast->next!=NULL) fast=fast->next;
            else return false;
        }while(slow!=fast);
        return true;
    }
};

环形链表Ⅱ

在这里插入图片描述

快慢指针摆放的位置以及走过路程的数学关系
在这里插入图片描述(图源力扣,侵删)

  • 先利用快慢指针到第一个结点,再把其中一个指针放回开头,每次1步,最终相遇点就是入环节点
/**
 * 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) {
        if(head==NULL) return NULL;
        ListNode *fast=head;
        ListNode *slow=head;
        do{
            if(slow->next!=NULL) slow=slow->next;
            else return NULL;
            if(fast->next!=NULL) fast=fast->next;
            else return NULL;
            if(fast->next!=NULL) fast=fast->next;
            else return NULL;
        }while(fast!=slow);
        slow=head;
        while(fast!=slow){
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
    }
};

相交链表

在这里插入图片描述

算法:变轨
在这里插入图片描述

  • 一句小评论(特别有意思):
  • “走到尽头见不到你,于是走过你来时的路,等到相遇时才发现,你也走过我来时的路。从此我们一路同行,直到生命尽头。”
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA==NULL||headB==NULL) return NULL;
        ListNode *p1=headA;
        ListNode *p2=headB;
        int cnt=0;
        do{
            if(p1==p2) return p1;
            if(p1->next!=NULL) p1=p1->next;
            else {
                p1=headB;
                cnt++;
            }
            if(p2->next!=NULL) p2=p2->next;
            else {
                p2=headA;
                cnt++;
            } 
        }while(cnt<=2);
        if(p1==p2) return p1;
        else return NULL;
    }
};

删除链表的倒数第N个结点

在这里插入图片描述

算法:快慢指针
先将fast移动n,然后慢指针也开始移动,当fast正好到结尾,慢指针正好到倒n+1个结点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if(head==NULL) return head;
        ListNode *fast=head;
        ListNode *slow=head;
        for(int i=0;i<n;i++){
            fast=fast->next;
        }
        if(fast==NULL) return head->next;//如果快指针为空,则要删除的是头结点,返回下一个结点的地址
        while(fast->next!=NULL){
            fast=fast->next;
            slow=slow->next;
        }
        slow->next=slow->next->next;
        return head;
    }
};

总结(双指针模板与注意事项)

模板:

// Initialize slow & fast pointers
ListNode* slow = head;
ListNode* fast = head;
/**
 * Change this condition to fit specific problem.
 * Attention: remember to avoid null-pointer error
 **/
while (slow && fast && fast->next) {
    slow = slow->next;          // move slow pointer one step each time
    fast = fast->next->next;    // move fast pointer two steps each time
    if (slow == fast) {         // change this condition to fit specific problem
        return true;
    }
}
return false;   // change return value to fit specific problem
    1. 在调用 next 字段之前,始终检查节点是否为空。
      获取空节点的下一个节点将导致空指针错误。例如,在我们运行 fast = fast.next.next 之前,需要检查 fast 和 fast.next 不为空。
    1. 仔细定义循环的结束条件。

反转链表

递归解决

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==NULL||head->next==NULL) return head;
        ListNode *p2=reverseList(head->next);
        head->next->next=head;
        head->next=NULL;
        return p2;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值