【算法笔记】链表

学习笔记:物理信息神经网络(PINN) PINN 的强大在于它打破了传统数值方法的限制,将神经网络的非线性拟合能力与物理方程的严谨性结合起来。它在处理高维、数据稀缺、复杂物理约束的场景下尤其出色。当然,PINN 也有收敛慢、梯度消失等挑战,比如,复杂 PDE 可能导致梯度传播困难,收敛慢(梯度消失)、于具有快速变化特征的系统,如冲击波,标准 PINN 可能精度不足,需要改进策略,比如自适应采样或多尺度特征提取。但随着研究深入,这些问题正在不断被解决。物理或化学方程为什么往往是偏微分方程?什么是物理信息神经网络(PINN)?x_%7Bi%7D。 阅读详情

判断链表是否为回文的,即从左往右看和从右往左看一样。
例如 1->2->2->1是回文的
1->2->3->2->1是回文的
1->3->2->1不是回文的
简单做法:首先准备一个栈,将链表的元素从左往右依次入栈,然后重新对比链表和栈顶元素。
双指针法:首先找到链表的中间位置mid,可以通过快慢指针实现
然后扭转mid以后的结点,mid的下一个结点指向空,然后两个指针从两边依次对比,最后再把链表恢复。

bool isHuiWen(Node* head) {//head->next是链表第一个元素
	Node* f = head;
	Node* s = head;
	while (f!=NULL && f->next != NULL) {
		f = f->next->next;
		s = s->next;
	}
	//此时s指向的就是中间结点,奇数个结点只有唯一一个中点,偶数个结点取中间两个都可以,这里取左边的
	Node* pre = NULL;
	Node* p = s;
	while (p != NULL) {//扭转结点
		Node* next = p->next;
		p->next = pre;
		pre = p;
		p = next;
	}
	//左右对比
	Node* l = head->next;
	Node* r = pre;
	bool flag = true;
	while (l != NULL && r != NULL) {
		if (l->data != r->data) {
			flag = false;
			break;
		}
		l = l->next;
		r = r->next;
	}
	//此时pre是最右边的结点
	p = pre;
	pre = NULL;
	while (p != NULL) {//恢复链表
		Node* next = p->next;
		p->next = pre;
		pre = p;
		p = next;
	}
	return flag;
}

给你一个链表,长度为偶数,假设链表为:L1->L2->L3->L4->R1->R2->R3->R4
要求将链表变为:L1->R4->L2->R3->L3->R2->L4->R1
分析:可以用到上一个题的双指针做法,先将链表转化为:
在这里插入图片描述
准备两个指针l和r分别指向链表两端,每次都穿插一个r结点。

void changeLink(Node* head) {
	Node* fast = head;
	Node* slow = head;
	while (fast != NULL && fast->next != NULL) {
		fast = fast->next->next;
		slow = slow->next;
	}
	Node* mid = slow;
	Node* pre = NULL;
	Node* p = mid;
	while (p != NULL) {
		Node* next = p->next;
		p->next = pre;
		pre = p;
		p = next;
	}
	Node* l = head->next;
	Node* r = pre;
	while (r!=mid) {
		Node* lnext = l->next;
		Node* rnext = r->next;
		l->next = r;
		r->next = lnext;
		l = lnext;
		r = rnext;
	}
}

链表划分:给定一个链表的头结点和划分值v,要求小于v的结点在左边,等于v的在中间,大于v的在右边(类似于快排的划分)
解1:将链表放数组,做划分,然后在用链表串起来。
解2:只用有限个变量:
准备6个指针分别是:小于区域的头指针和尾指针,等于区域的头指针和尾指针,大于区域的头指针和尾指针。初始都为空
然后从左往右遍历链表,如果小于v,则判断小于区域的头指针是否空,若为空,则头指针和尾指针都指向该结点,否则,尾指针的next指向该结点,尾指针指向该结点……
最后小于区域的尾指针指向等于区域的头指针,等于区域的尾指针指向大于区域的头指针。
有陷阱:小于区域可能为空,等于区域也可能为空……

Node* change(Node* head,int v) {
	Node* sHead = NULL;
	Node* sTail = NULL;
	Node* mHead = NULL;
	Node* mTail = NULL;
	Node* eHead = NULL;
	Node* eTail = NULL;
	Node* p = head;
	while (p != NULL) {
		Node* next = p->next;
		if (p->val < v) {
			if (sHead == NULL) {
				sHead = p;
				sTail = p;
				
			}
			else {
				sTail->next = p;
				sTail = p;
			}
		}
		else if (p->val == v) {
			if (mHead == NULL) {
				mHead = p;
				mTail = p;
			}
			else {
				mTail->next = p;
				mTail = p;
			}
		}
		else {
			if (eHead == NULL) {
				eHead = p;
				eTail = p;
			}
			else {
				eTail->next = p;
				eTail = p;
			}
		}
		p->next = NULL;
		p = next;
	}
	//连接
	if (sTail != NULL) {//小于区域不为空
		sTail->next = mHead;
		if (mTail == NULL) {//等于区域为空
			mTail = sTail;//sTail去连大于区域的头
		}
	}

	if (mTail != NULL) {
		mTail->next = eHead;
	}
	return sHead != NULL ? sHead : (mHead != NULL ? mHead : eHead);

}

拷贝链表,现在每个结点有两个指针,一个next(下一个),一个random(随意指)

class Node {
public:
	int val;
	Node* next;
	Node* random;
	Node() {
		val = 0;
		next = NULL;
		random = NULL;
	}
	Node(int val) :val(val) {
		next = NULL;
		random = NULL;
	}
};

现在要求赋值拷贝一个和原来一样的链表
解1:准备一张哈希表,key为原结点,value为新结点,遍历链表,将新结点都建出来,并且值都和原结点一样,但指针都悬空
然后取每一对键值对,新结点的next就是原来结点的next对应的value,新结点的random就是原来结点的random对应的value。

Node* copyList(Node* head) {
	unordered_map<Node*, Node*>map;
	Node* p = head;
	while (p != NULL) {
		map.emplace(p, new Node(p->val));
		p = p->next;
	}
	for (auto it = map.begin(); it != map.end(); ++it) {
		Node* old = (*it).first;
		Node* newNode = (*it).second;
		if (old->next == NULL) {
			newNode->next = NULL;
		}
		else {
			newNode->next = map[old->next];
		}
		if (old->random == NULL) {
			newNode->random = NULL;
		}
		else {
			newNode->random = map[old->random];
		}
		
		
	}
	return map[head];
}

解2:只用有限几个变量,解1是人为的构造老新结点的对应关系,该解法在结构上构造对应关系。
例如
在这里插入图片描述
现在对链表做如下调整:
每个结点后面连接一个与该节点值相同的结点,新结点next指向原来结点的next,新结点的random暂时悬空,如下图

在这里插入图片描述
从头开始遍历,每次访问两个结点,例如1和1’,1’的random就指向1的random指向结点的下一个结点,如上图,这样就将新结点random全部设置好。此时结点next还没设置好。
从头开始遍历,每次访问两个结点,例如1和1’,1的next等于1’的next,1’的next等于1’的next的next
所以总共需要三个循环

Node* copyList2(Node* head) {
	Node* p = head;
	while (p != NULL) {//插入
		Node* node = new Node(p->val);
		node->next = p->next;
		p->next = node;
		p = node->next;	
	}
	p = head;
	
	while (p != NULL) {//设置random
		Node* q = p->next;
		if (p->random == NULL) {
			q->random = NULL;
		}
		else {
			q->random = p->random->next;
		}
		p = q->next;
	}
	p = head;
	Node* newHead = head->next;
	while (p != NULL) {//设置next
		Node* q = p->next;
		p->next = q->next;
		if (q->next != NULL) {
			q->next = q->next->next;
		}
		p = p->next;
	}
	return newHead;
}

时间复杂度O(N)
203. 移除链表元素

  • 链表的创建
struct ListNode {
	int val;
	ListNode* next;
	//构造函数
	ListNode() : val(0), next(nullptr) {};//nullptr代表空指针
	ListNode(int x) : val(x), next(nullptr) {}
	ListNode(int x, ListNode* next) : val(x), next(next) {}
}
  • 链表删除:对于单结点,需要找到删除结点的上一个结点,由于头结点没有上一个结点,可以采取以下两种方法。
    1.对头结点特殊处理
ListNode* removeElements(ListNode* head, int val) {  
        while(head!=nullptr&& head->val==val){
            ListNode* temp=head;
            head=head->next;
            delete temp;
        }
        ListNode* cur=head;
        while(cur!=nullptr && cur->next!=nullptr){
            if(cur->next->val==val){
                ListNode* temp=cur->next;
                cur->next=temp->next;
                delete temp;
            }
            else{
                cur=cur->next;
            }
        }
        return head;
    }

2.创建一个虚拟头结点

ListNode* removeElements(ListNode* head, int val) {  
        ListNode* h0=new ListNode();
        h0->next=head;
        ListNode* cur=h0;
        while(cur!=nullptr && cur->next!=nullptr){
            if(cur->next->val==val){
                ListNode* temp=cur->next;
                cur->next=temp->next;
                delete temp;
            }
            else{
                cur=cur->next;
            }
        }
        return h0->next;//返回真正的头结点
    }

707. 设计链表

综合考察链表的各项操作
插入删除建一个虚拟头结点更方便

class MyLinkedList {

public:
    struct LinkedNode {
        int val;
        LinkedNode* next;
        LinkedNode(int val) :val(val), next(nullptr) {}
    };
    MyLinkedList() {
        size = 0;
        virHead = new LinkedNode(0);
    }

    int get(int index) {
        if (index >= size || index < 0) {
            return -1;
        }
        LinkedNode* cur = virHead->next;
        while (index--) {
            cur = cur->next;
        }
        return cur->val;
    }

    void addAtHead(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        newNode->next = virHead->next;
        virHead->next = newNode;
        size++;
    }

    void addAtTail(int val) {
        LinkedNode* cur = virHead;
        while (cur->next != nullptr) {
            cur = cur->next;
        }
        LinkedNode* newNode = new LinkedNode(val);
        newNode->next = cur->next;
        cur->next = newNode;
        size++;
    }

    void addAtIndex(int index, int val) {
        if (index < 0) {
            addAtHead(val);
        }
        else if (index == size) {
            addAtTail(val);
        }
        else if (index > size) {
            return;
        }
        else {
            LinkedNode* cur = virHead;
            for (int i = 0; i < index; i++) {
                cur = cur->next;
            }
            LinkedNode* newNode = new LinkedNode(val);
            newNode->next = cur->next;
            cur->next = newNode;
            size++;
        }
    }

    void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        LinkedNode* cur = virHead;
        for (int i = 0; i < index; i++) {
            cur = cur->next;
        }
        LinkedNode* temp = cur->next;
        cur->next = temp->next;
        delete temp;
        size--;
    }
private:
    int size;
    LinkedNode* virHead;
};

206. 反转链表

翻转链表:设三个指针,一个指向当前结点,一个指向前一个结点,另一个暂存当前结点的下一个结点。
流程:cur->next=pre,然后pre和cur后移,一直循环,终止条件是cur=nullptr,此时pre为翻转后的头结点。


```/**
 * 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) {
        ListNode* cur=head;
        ListNode* pre=nullptr;
        while(cur!=nullptr){
            ListNode* temp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=temp;
        }
        head=pre;
        return head;
    }
};

解2 递归写法
从左往右翻转,最后返回的就是翻转后的头结点,一直返回到主函数即可。

/**
 * 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* reverse(ListNode* pre,ListNode* cur){
        if(cur==nullptr){
            return pre;//翻转后的头结点
        }
        ListNode* temp=cur->next;
        cur->next=pre;
        pre=cur;
        cur=temp;
        return reverse(pre,cur);
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(nullptr,head);
    }
};

第二种递归写法
从右往左翻转,右边是已经翻转好的,左边待翻转,每个子函数都向上返回翻转后的头结点。

/**
 * 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 == nullptr || head->next==nullptr){//终止条件
            return head;
        }
        ListNode* last=reverseList(head->next);//翻转后的头结点
        head->next->next=head;
        head->next=nullptr;
        return last;//返回给上一层头结点


    }
};

24. 两两交换链表中的节点

涉及到头结点可能会改变的添加一个虚拟头结点会更方便
交换涉及到的中间变量可以通过画图来找,一般指向发生变化的结点所指向的结点需要保存。

/**
 * 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* swapPairs(ListNode* head) {
       ListNode* virHead=new ListNode();//由于头结点会改变,设一个虚拟头结点
       virHead->next=head;
       ListNode* cur=virHead;//cur处于一对结点的前一个位置
       while(cur->next!=nullptr && cur->next->next !=nullptr){
           //交换涉及到3个中间变量需要保存
           ListNode* firstPos=cur->next;//原来第1号位置
           ListNode* secondpos=firstPos->next;//原来第2号位置
           ListNode* next=secondpos->next;//下一对结点的1号位置
           cur->next=secondpos;
           secondpos->next=firstPos;
           firstPos->next=next;
           cur=firstPos;
       }
       return virHead->next;
    }
    
};

不设虚拟头结点:由于在第一次交换时,2号结点是新的头结点,所以需要一个变量保存下来

/**
 * 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* swapPairs(ListNode* head) {
        ListNode* last=nullptr;//交换后cur的前结点
        ListNode* cur=head;//当前结点
        ListNode* newHead=nullptr;//新的头结点
        while(cur!=nullptr && cur->next!=nullptr){//保证是两两交换
            ListNode* next=cur->next->next;//下一对结点的首结点
            ListNode* first=cur;//1号结点
            ListNode* second=cur->next;//2号结点
            second->next=first;//交换
            first->next=next;//保证最后一对结点的first->next==nullptr
            if(last!=nullptr){
                last->next=second;//连接前结点
            }else{
                newHead=second;//保存新的头结点
            }
            last=first;//更新cur的前结点
            cur=next;
        }
        return newHead;
    }
};

递归写法:对于这种链表的递归写法,首先要明确操作的顺序是什么样的,例如本题,如果要返回交换后的头结点 自然应该从后往前进行,下一层要返回给上一层交换后的头结点。

/**
 * 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* f(ListNode* head){//返回从head开始交换后的头结点
        if(head==nullptr || head->next==nullptr){//不足两个结点没法交换
            return head;
        }
        ListNode* first=head;//原来1号位置
        ListNode* second=head->next;//原来2号位置
        ListNode* next=f(second->next);//下一层交换后的头结点
        second->next=first;
        first->next=next;
        return second;
        
    }
    ListNode* swapPairs(ListNode* head) {
        return f(head);
    }
};

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

分析:
解1 :对于单链表,找第i个结点好找,但找倒数第k个结点,可以通过先计算出一个多少个结点,然后计算出要找的结点位于第j个结点

/**
 * 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) {
        ListNode* virHead=new ListNode();
        virHead->next=head;
        
        ListNode* tail=virHead;
        int sum=0;//求结点的个数
        while(tail->next!=nullptr){
            tail=tail->next;
            sum++;
        }
        int index=sum-n;//位于第index位置
        ListNode* cur=virHead;
        while(index--){
            cur=cur->next;
        }
        ListNode* temp=cur->next; 
        cur->next=cur->next->next;
        delete temp;
        return virHead->next;


    }
};

解2 双指针法
设两个指针 slow 和fast,要找倒数第n个结点,始终保持slow与fast之间的距离为n,(slow在左,fast在右),当fast指向nullptr是,slow就是倒数第n个结点。
本题要删除倒数第n个结点,因此实际上要找到倒数第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) {
        ListNode* virHead=new ListNode();
        virHead->next=head;
        ListNode* slow=virHead;
        ListNode* fast=virHead;
        for(int i=0;i<n+1;i++){
             fast=fast->next;
        }
        while(fast!=nullptr){//循环终止时slow指向要删除结点的上一个结点
            slow=slow->next;
            fast=fast->next;
        }
          ListNode* temp=slow->next;
          slow->next=temp->next;
          delete temp; 
        return virHead->next;

    }
};

面试题 02.07. 链表相交

分析:若存在相交结点,那么一定存在一段结点重合。因此可以令两链表的尾部对齐,设两个指针从前往后查找,找到相同的即是相交结点。

/**
 * 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;
        }
        int lena=0;
        int lenb=0;
        ListNode* cura=headA;
        while(cura!=NULL){//求A的长度
            lena++;
            cura=cura->next;
        }
        ListNode* curb=headB;
        while(curb!=NULL){//求B的长度
            lenb++;
            curb=curb->next;
        }
        if(lenb<lena){//长的对齐
            cura=headA;
            int index=lena-lenb;
            while(index--){
                cura=cura->next;
            }
            curb=headB;
            while(cura!=NULL){
                if(cura!=curb){
                    cura=cura->next;
                    curb=curb->next;
                }
                else{
                    return cura;
                }
            }
            return NULL;
        }
        else{
            curb=headB;
            int index=lenb-lena;
            while(index--){
                curb=curb->next;
            }
            cura=headA;
            while(cura!=NULL){
                if(cura!=curb){
                    cura=cura->next;
                    curb=curb->next;
                }
                else{
                    return cura;
                }
            }
            return NULL;
        }
        return NULL;
    }
};

拓展:如果单链表有环呢,如何求相交结点?
这里分三种情况:
第一种:两个链表都有环,但不相交
在这里插入图片描述
第二种情况:两个链表有相同的入环结点
在这里插入图片描述
第三种情况

在这里插入图片描述
其中第一种和第三种情况可以放在一起:
从某一个链表的入口结点开始不断往后走,如果中途与另一个链表的入口结点相遇则是第三种情况,否则就回到了本结点不相交。
第二种情况转化为从头结点到入口结点组成的链表求相交结点,就是本题的做法。

142. 环形链表 II

第一步 先判断是否有环
设两个指针,一个指针一次走一个结点,另一个一次走两个结点,当slow指针也进入环时,由于每走一次,两指针的距离就减一,最终一定会减为0,即相遇;若没有环,快指针会走到尾部。
第二步 找入口结点
第一步可以得到相遇结点的位置,接下来通过列式求入口结点
设从头结点到入口结点的距离为L,从入口结点到相遇结点的距离为X,环的长度为C。
在这里插入图片描述
因此快指针走过的距离:L+nC+X,慢指针走过的距离:L+X,因为快指针每次走的距离是慢指针的2倍,所以L+nC+X=2(L+X),整理得:L=nC-X。
在这里插入图片描述
因此令一个指针指向头结点,另一个指针指向相遇位置,两个指针同时移动一个结点,最终一定会相遇,且相遇的位置即为入口结点的位置。

/**
 * 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) {
            ListNode* slow=head;
            ListNode* fast=head;
            bool flag=false;
            while(fast!=NULL && fast->next!=NULL){//判断是否有环
                slow=slow->next;
                fast=fast->next->next;
                if(slow==fast){
                    flag=true;
                    break;
                }
            }
            if(!flag){
                return NULL;
            }
            slow=head;
            while(fast!=slow){
                fast=fast->next;
                slow=slow->next;
            }
            return fast;
    }
};

总结

  1. 涉及到头结点可能变化的设一个虚拟头结点会比较方便。
  2. 要找倒数第n个结点,设两个指针,保持两指针的距离为n,当fast指针为nullptr时,slow即为倒数第n个结点。
  3. 判断是否有环,设两个指针slow、fast,slow移动步长1,fast移动步长2.
ardupilot开发 --- mavlink签名加密 篇 ardupilot开发 --- mavlink签名加密 阅读详情

相关推荐

Win10系统权限深度解析:如何安全地将C盘所有者从TrustedInstaller变更为Administrators

本文深入解析了Win10系统中C盘文件权限管理的核心机制,解释了为何管理员账户(Administrators)默认无法修改由TrustedInstaller保护的系统文件。文章在强调安全风险的前提下,详细提供了通过图形界面和命令行两种方式,将文件或文件夹所有权从TrustedInstaller安全变更为Administrators的实操步骤,并给出了关键的风险预警与权限恢复方法。

weixin_29305313的博客 548

leetcode算法题解整理之链表专题部分

算法题解之链表专题 链表数据结构 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){} }; 19. 删除链表的倒数第 N 个结点 【题目描述】:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 【分析

weixin_43488529的博客 669

保姆级教程:用Smaart7和你的USB声卡搞定现场音响系统调试(附频谱与延时测试避坑指南)

本文提供Smaart7与USB声卡协同工作的现场音响系统调试指南,涵盖硬件连接、频谱分析、延时校准等关键步骤。通过详细的操作流程和常见问题解决方案,帮助音响工程师快速掌握专业测量技术,确保演出音质达到最佳状态。

weixin_29290259的博客 422

对于ListNode() : val(0), next(nullptr) {}写法理解

链表初始化定义

hy091997的博客 1686

vos如何对接okcc(保姆级教程)

1.添加账户 点击 系统->账户管理 [图片] 2.创建费率 系统->费率管理 点击添加

qq_46333281的博客 3453

SpringBoot3 + OAuth2.1实战:5分钟搞定授权码模式(含完整代码)

本文详细介绍了如何在SpringBoot3环境中快速实现OAuth2.1的授权码模式,包括环境配置、核心安全实现及完整代码示例。通过Spring Security集成,开发者可以高效构建企业级安全认证系统,解决版本兼容性问题,提升开发效率。

weixin_29216353的博客 138

Leetcode链表篇总结(C++)

文章目录一、基础知识二、经典题目1、 203:移除链表元素 一、基础知识 1、链表的定义 单链表:(leetcode上的实现) * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {}

weixin_42783170的博客 3931

机器人动力学仿真软件:Webots_(14).机器人声音仿真

Webots 中的声音仿真主要通过Sound和两种节点来实现。Sound节点用于播放预定义的音频文件,而节点则允许在仿真过程中动态生成和播放声音。这些节点可以用于模拟机器人的语音输出、报警声、环境噪音等。以下是一个示例,展示如何在控制器代码中播放预定义的声音。// 控制器代码(.c) # include <webots/robot.h> # include <webots/sound.h> # define TIME_STEP 64 const char * sound_name = "sound";

kkchenjj的博客 1311

Leetcode初级算法——链表

删除链表中的节点 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为要被删除的节点。 现有一个链表 -- head = [4,5,1,9],它可以表示为:​示例 : 输入:head = [4,5,1,9], node = 5输出:[4,1,9]解释:给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 提示: 链表至少包含两个节点。 链表中所有节点的值都是唯一的。 给定的节点为非末尾节点并且一定是链表中..

杉杉coming! 912

YOLOv8【第一章:基础入门篇·第1节】一文搞定,核心架构深度解析与环境配置!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏,该专栏专注于分享我在YOLOv8目标检测模型中的实战经验,涵盖从入门基础到深度优化的全方位解决方案。无论你是计算机视觉的新手,还是具有多年深度学习经验的专家,本专栏都将为你提供高效、可复现的技术方案,助你掌握YOLOv8的核心技术,提升目标检测性能,突破瓶颈,优化模型,并加速项目开发🚀!

**My Coding Family** 2101

基于YOLOv5的空间目标智能监测系统:航天器与太空碎片识别技术实现

做完这个项目,你会发现自己完整走过了“数据采集→标注→模型训练→功能集成→界面开发”的毕设全流程,这不仅是技术能力的证明,更是对“技术守护宇宙安全”这一理念的实践。答辩时,你可以重点讲这几点:系统解决了航天监测的哪些痛点、YOLOv5在太空目标检测中的性能优势、系统未来能怎么优化(比如对接航天监测网络、实现实时轨道预测)。未来,这个系统还能往“更智能”的方向发展:比如结合轨道计算预测碰撞风险、开发移动端APP让天文爱好者参与太空垃圾上报、在航天任务中实现全自动避障决策……想象空间很大。

m0_64661770的博客 109

c++中ListNode定义与使用与leecode ListNode算法题

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) {} // 初始化时可以使用:该方式将x和next赋值给val和next }; //main函数 ListNode* l3 = new ListNode(12

qq_36694183的博客 7295

android 9.0Settings休眠时间项(屏幕超时)添加永不休眠功能

在9.0的系统产品开发中,系统中默认息屏时间为1分钟,可以通过在Setting中的息屏时间选项设置对应的息屏时间,但是在开发平板类的产品中,需要实现永不休眠的功能,所以需要在Settings中的息屏时间中添加永不休眠时间这一项来实现这个功能,接下来看息屏时间的相关功能,来添加这个功能

安卓兼职framework和app工程师的博客 2055

左程云老师算法讲解笔记【009单链表反转】

图解链表反转

qq_37685626的博客 416

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【算法笔记】有人看海,有人被爱,有人做不出 leetcode 第一题(链表专题)

链表理论基础、移除链表元素、设计链表、反转链表、两两交换链表中的节点、删除链表中的倒数第 n 个数、链表相交、环形链表Ⅱ

OuO-1 的博客 1253

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

[算法学习笔记] 《Hello算法》第4章 数组与链表

本系列为《Hello算法》学习笔记,仅供学习,不做商用,如有侵权,联系我删除即可!数组(array)是一种线性数据结构,其将相同类型的元素存储在连续的内存空间中。我们将元素在数组中的位置称为该元素的索引(index)。下图展示了数组的主要概念和存储方式。数组的两种初始化方式:无初始值、给定初始值。在未指定初始值的情况下,大多数编程语言会将数组元素初始化为 0 : 2. 访问元素 数组元素被存储在连续的内存空间中,这意味着计算数组元素的内存地址非常容易。给定数组内存地址(首元素内存地址)和某个元素的

努力学习 1372

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

(习题笔记)C++算法竞赛语法基础:结构体,类,指针,引用,链表

我算法属实是一个小白,现在入门,意外发现这里很方便记笔记,就将自己的学习笔记放了上来,方便随时随地复习。现在发现还可以督促我学习哈哈哈,希望大家多多指教啦~,有什么好的学习方法大佬们若愿指点一二,hong感激不尽!算法真的感觉难,链表一道题我都要想好久,做不出再看讲解,然后自己再理解,虽道阻且长,但还是勇往直前吧!注:这里收录的是我做不出、做错之类的我自己需要回顾的题目。

honghong______的博客 1678

《算法笔记》链表

目录动态链表的操作(增删改查)静态链表 动态链表的操作(增删改查) 链表一般是带头结点的链表,头结点并没有数据; 遍历链表时,先令p = head - > next,,只要p非空,就可以一直循环; 删除链表元素时,需要两个指针,一个指向将要删除的元素,另一个指向删除元素的前驱; 增加元素时,要先找到目标元素,然后新建一个节点,在这个目标元素的后面加上新建节点 #include <io...

hjyp的博客 201

《算法笔记》——链表

链表一.链表的概念二. 使用malloc 函数或者new 运算符为链表结点分配内存空间2.1 malloc2.2 new运算符2.3 内存泄漏三.链表的基本操作3.1 创建链表3.2 查找元素 一.链表的概念 1.链表由若干个结点组成(每个结点代表一个元素),且结点在内存中的存储位置通常是不连续的。 2.链表的两个结点之间一般通过一个指针来从一个结点指向另一个结点,因此链表的结点一般由两部分构成,即数据域和指针域。数据域存放结点要存储的数据,指针域指向下一个结点的地址。这样就会产生从某个结点开始的,由指针连

Concise200的博客 330

算法笔记——链表

基本操作 创建链表:尾插法和头插法 尾插法 #include<iostream> #include<stdio.h> using namespace std; struct node { int data; node *next; }; //尾插法创建链表 node * create(int Array[]) { node *head = n...

weixin_44698281的博客 255

算法笔记-链表

链表是有序的列表,但是它在内存中是存储如下(你中有我,我中有你,铁索连环) 1)链表的各个节点不一定是连续存储. 2)链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定 单链表(带头结点) 逻辑结构示意图如下: 3)实现代码: public class LinkListDemo { //节点类 public class Node { protecte...

好久不见的博客 182

算法课程笔记——基础数据结构-链表、栈、队列

算法课程笔记——基础数据结构-链表、栈、队列。

2302_79123319的博客 323

数据结构与算法学习笔记----链表

@ author: 明月清了个风。

weixin_60278491的博客 1064

算法学习 (门徒计划)1-1 链表 学习笔记

链表的基础概念和常见题目的解决思路

ex_xyz的博客 1595

数据结构与算法——LeetCode刷题笔记(二):链表

数据结构与算法——LeetCode刷题笔记(二):链表

weixin_42923076的博客 285

笔记:链表算法之反转链表

链表算法一:反转链表 题目:给定一个带头结点的单链表,按照其逆序输出。 输入:head->1->2->3->4->5->6->7 输出:head->7->6->5->4->3->2->1 注意:由于链表和数组结构不同,单链表中每个结点的地址都储存在其前结点的指针域中,因此,访问任何一个结点只能从链表的头指针开始进行...

weixin_43824846的博客 224
上一篇: 【算法笔记】数组篇-双指针以及滑动窗口
下一篇: 【算法笔记】哈希表
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值