当前位置: 首页 > news >正文

【数据结构】链表应用1

链表应用

  • 面试题 02.02.返回倒数第k个节点
    • 题目描述
    • 思路
    • 解题过程
    • 复杂度
  • 查找相同后缀
    • 题目描述
    • 解题思路
    • 完整代码:
  • 删除绝对值相等的节点
    • 题目描述
    • 解题思路
    • 代码

面试题 02.02.返回倒数第k个节点

题目描述

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

注意: 本题相对原题稍作改动

示例:

输入: 1->2->3->4->5 和 k = 2
输出: 4

说明:
给定的 k 保证是有效的。

思路

使用快慢指针

解题过程

  • 初始化两个快慢指针,都指向head(注意不是head->nert,否则会报错说指向空指针)
  • 先让快指针走k步;再快慢指针同步走;直到快指针指向NULL;此时慢指针的数据就是期望数据。

复杂度

  • 时间复杂度: O(n)
  • 空间复杂度: O(1)
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
int kthToLast(struct ListNode* head, int k)
{if (head ==NULL)return 0;struct ListNode *fast = head;struct ListNode *slow = head;for (int i = 0; i < k; i ++){if (fast ==NULL)return 0;fast = fast->next;}while (fast != NULL){fast = fast->next;slow = slow->next;}return slow->val;
}作者:北国无红豆
链接:https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/solutions/3050388/kuai-man-zhi-zhen-jie-jue-dao-shu-di-kge-qdml/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

注意初始化的时候要写指向head,不能指向head->next,否则会不通过,报警告,说指向空指针

    struct ListNode *fast = head;struct ListNode *slow = head;

放一份完整的代码,这样写(初始化指向head->next)也能找到期望数据,这里不太理解

#include <stdio.h>
#include <stdlib.h>typedef int ElemType; // 定义元素类型typedef struct node // 定义节点类型
{ElemType data;struct node *next;
} Node;/* 初始化一个单链表-造一个头节点 */
Node *InitList()
{Node *head = (Node *)malloc(sizeof(Node)); // 为头节点分配内存head->data = 0;                            // 头节点的数据域为0head->next = NULL;                         // 头节点的指针域为空return head;                               // 返回头节点
}
/*单链表 - 头插法*/
int InsertHead(Node *L, ElemType e)
{Node *p = (Node *)malloc(sizeof(Node)); // 创建一个新的节点p->data = e;                            // 在新节点的数据域存入数据ep->next = L->next;                      // 新节点的指针域指向头节点的下一个节点(把L的NULL复制给新节点)L->next = p;                            // 头节点的指针域指向新节点return 1;                               // 返回1表示成功
}
/* 单链表 - 遍历 */
void TraverseList(Node *L)
{Node *p = L->next; // 从头节点的下一个节点开始遍历while (p != NULL)  // 遍历到链表末尾{printf("%d ", p->data); // 输出节点的数据域p = p->next;            // 移动到下一个节点}printf("\n"); // 换行
}/* 单链表 - 尾插法 */
// 获取尾节点地址
Node *GetTail(Node *List)
{Node *p = List;         // 从头节点开始遍历while (p->next != NULL) // 遍历到链表末尾{p = p->next; // 移动到下一个节点}return p; // 返回尾节点
}/*** @Description:单链表 - 尾插法插入数据* @param {Node} *tail   尾节点* @param {ElemType} e   插入的数据* @return {*}           返回新的尾节点*/
Node *InsertTail(Node *tail, ElemType e)
{Node *p = (Node *)malloc(sizeof(Node)); // 创建一个新的节点p->data = e;                            // 在新节点的数据域存入数据etail->next = p;                         // 尾节点的指针域指向新节点p->next = NULL;                         // 新节点的指针域为空return p;                               // 返回新的尾节点
}/*** @Description:单链表 - 在指定位置插入数据* @param {Node} *L     单链表的头节点* @param {int} pos     位置* @param {ElemType} e  插入的数据* @return {*}*/
int InsertPosNode(Node *L, int pos, ElemType e)
{// 用来保存插入位置的前驱节点Node *p = L; // 从头节点开始遍历int i = 0;// 遍历链表-找到插入位置的前驱节点while (i < pos - 1) // 遍历到插入位置的前驱节点{p = p->next; // 移动到下一个节点i++;if (p == NULL) // 判断是否到达链表末尾{printf("插入位置不合法\n");return 0;}}Node *newnode = (Node *)malloc(sizeof(Node)); // 创建一个新的节点newnode->data = e;                            // 在新节点的数据域存入数据enewnode->next = p->next;                      // 新节点的指针域指向插入位置的前驱节点的下一个节点p->next = newnode;                            // 插入位置的前驱节点的指针域指向新节点return 1;
}/*** @Description:单链表 - 删除指定位置的节点* @param {Node} *L 单链表的头节点* @param {int} pos 位置* @return {*}       返回1表示成功*/
int DeletePosNode(Node *L, int pos)
{// 用来保存删除位置的前驱节点Node *p = L; // 从头节点开始遍历int i = 0;// 遍历链表-找到删除节点的前驱节点while (i < pos - 1) // 遍历到删除位置的前驱节点{p = p->next; // 移动到下一个节点i++;if (p == NULL) // 判断是否到达链表末尾{printf("删除位置不合法\n");return 0;}}if (p->next == NULL) // 判断删除位置是否合法{printf("删除位置不合法\n");return 0;}Node *q = p->next; // 保存要删除的节点的地址p->next = q->next; // 删除节点的前驱节点的指针域 指向 删除节点的下一个节点free(q);           // 释放删除节点的内存return 1; // 返回1表示成功
}int GetListLength(Node *L)
{int length = 0;Node *p = L; // 从头节点开始遍历,头节点算在内while (p != NULL){p = p->next;length++;}return length;
}void FreeList(Node *L)
{Node *p = L->next; // 从头节点的下一个节点开始遍历,头节点不需要释放Node *q = NULL;    // 用来保存下一个节点的地址,q能掌握下一个节点的地址,这是灵魂所在while (p != NULL){q = p->next; // 保存下一个节点的地址free(p);     // 释放当前节点的内存p = q;       // 移动到下一个节点}L->next = NULL; // 头节点的指针域为空
}// 查找倒数第k个节点
int findNodeFS(Node *L, int k)
{Node *fast = L->next;Node *slow = L->next;for (int i = 0; i < k; i++){fast = fast->next;}while (fast != NULL){fast = fast->next;slow = slow->next;}printf("倒数第%d个节点值为:%d\n", k, slow->data);return 1;
}int main()
{Node *list = InitList();Node *tail = GetTail(list);tail = InsertTail(tail, 10);tail = InsertTail(tail, 20);tail = InsertTail(tail, 30);tail = InsertTail(tail, 40);tail = InsertTail(tail, 50);tail = InsertTail(tail, 60);tail = InsertTail(tail, 70);TraverseList(list);findNodeFS(list, 3);return 0;
}

输出数据:

10 20 30 40 50 60 70
倒数第3个节点值为:50请按任意键继续. . .

查找相同后缀

题目描述

【2012】假定采用带头节点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀存储空间,例如,“loading”“being”的存储映像如下图所示。

在这里插入图片描述

设str1和str2分别指向两个单词所在单链表的头节点,链表节点结构为data | next,请设计一个时间上尽可能高效的算法,找出由str1和str2所指向两个链表共同后缀的起始位置(如图字符i所在节点的位置p)。要求:

  1. 描述算法的基本设计思想;
  2. 根据设计思想,采用c/C++/Java语言描述,关键之处给出注释
  3. 说明你所设计算法的时间复杂度

解题思路

  1. 分别求出两个链表的长度mn
  2. Fast指向较长的链表,先走m-n或者n-m
  3. 同步移动指针,判断他们是否指向同一个节点

在这里插入图片描述

在这里插入图片描述

完整代码:

#include <stdio.h>
#include <stdlib.h>typedef char ElemType; // 定义元素类型typedef struct node // 定义节点类型
{ElemType data;struct node *next;
} Node;/* 初始化一个单链表-造一个头节点 */
Node *InitList()
{Node *head = (Node *)malloc(sizeof(Node)); // 为头节点分配内存head->data = 0;                            // 头节点的数据域为0head->next = NULL;                         // 头节点的指针域为空return head;                               // 返回头节点
}// 初始化节点(带节点数据域参数)
Node *InitListWithElem(ElemType e)
{Node *node = (Node *)malloc(sizeof(node)); // 为节点分配内存node->data = e;                            // 节点的数据域为enode->next = NULL;                         // 节点的指针域为空return node;                               // 返回节点
}/*单链表 - 头插法*/
int InsertHead(Node *L, ElemType e)
{Node *p = (Node *)malloc(sizeof(Node)); // 创建一个新的节点p->data = e;                            // 在新节点的数据域存入数据ep->next = L->next;                      // 新节点的指针域指向头节点的下一个节点(把L的NULL复制给新节点)L->next = p;                            // 头节点的指针域指向新节点return 1;                               // 返回1表示成功
}
/* 单链表 - 遍历 */
void TraverseList(Node *L)
{Node *p = L->next; // 从头节点的下一个节点开始遍历while (p != NULL)  // 遍历到链表末尾{printf("%c", p->data); // 输出节点的数据域,这里是%c,因为ElemType是char类型p = p->next;           // 移动到下一个节点}printf("\n"); // 换行
}/* 单链表 - 尾插法 */
// 获取尾节点地址
Node *GetTail(Node *List)
{Node *p = List;         // 从头节点开始遍历while (p->next != NULL) // 遍历到链表末尾{p = p->next; // 移动到下一个节点}return p; // 返回尾节点
}/*** @Description:单链表 - 尾插法插入数据* @param {Node} *tail   尾节点* @param {ElemType} e   插入的数据* @return {*}           返回新的尾节点*/
Node *InsertTail(Node *tail, ElemType e)
{Node *p = (Node *)malloc(sizeof(Node)); // 创建一个新的节点p->data = e;                            // 在新节点的数据域存入数据etail->next = p;                         // 尾节点的指针域指向新节点p->next = NULL;                         // 新节点的指针域为空return p;                               // 返回新的尾节点
}/*** @Description:单链表 - 在链表尾部插入节点* @param {Node} *tail   链表尾部节点* @param {Node} *node   要插入的节点* @return {Node *}      插入节点后的链表尾部节点*/
Node *InsertTailWithNode(Node *tail, Node *node)
{tail->next = node; // 尾节点的指针域指向要插入的节点node->next = NULL; // 要插入的节点的指针域为空return node;       // 返回新的尾节点
}/*** @Description:单链表 - 在指定位置插入数据* @param {Node} *L     单链表的头节点* @param {int} pos     位置* @param {ElemType} e  插入的数据* @return {*}*/
int InsertPosNode(Node *L, int pos, ElemType e)
{// 用来保存插入位置的前驱节点Node *p = L; // 从头节点开始遍历int i = 0;// 遍历链表-找到插入位置的前驱节点while (i < pos - 1) // 遍历到插入位置的前驱节点{p = p->next; // 移动到下一个节点i++;if (p == NULL) // 判断是否到达链表末尾{printf("插入位置不合法\n");return 0;}}Node *newnode = (Node *)malloc(sizeof(Node)); // 创建一个新的节点newnode->data = e;                            // 在新节点的数据域存入数据enewnode->next = p->next;                      // 新节点的指针域指向插入位置的前驱节点的下一个节点p->next = newnode;                            // 插入位置的前驱节点的指针域指向新节点return 1;
}/*** @Description:单链表 - 删除指定位置的节点* @param {Node} *L 单链表的头节点* @param {int} pos 位置* @return {*}       返回1表示成功*/
int DeletePosNode(Node *L, int pos)
{// 用来保存删除位置的前驱节点Node *p = L; // 从头节点开始遍历int i = 0;// 遍历链表-找到删除节点的前驱节点while (i < pos - 1) // 遍历到删除位置的前驱节点{p = p->next; // 移动到下一个节点i++;if (p == NULL) // 判断是否到达链表末尾{printf("删除位置不合法\n");return 0;}}if (p->next == NULL) // 判断删除位置是否合法{printf("删除位置不合法\n");return 0;}Node *q = p->next; // 保存要删除的节点的地址p->next = q->next; // 删除节点的前驱节点的指针域 指向 删除节点的下一个节点free(q);           // 释放删除节点的内存return 1; // 返回1表示成功
}int GetListLength(Node *L)
{int length = 0;Node *p = L; // 从头节点开始遍历,头节点算在内while (p != NULL){p = p->next;length++;}return length;
}void FreeList(Node *L)
{Node *p = L->next; // 从头节点的下一个节点开始遍历,头节点不需要释放Node *q = NULL;    // 用来保存下一个节点的地址,q能掌握下一个节点的地址,这是灵魂所在while (p != NULL){q = p->next; // 保存下一个节点的地址free(p);     // 释放当前节点的内存p = q;       // 移动到下一个节点}L->next = NULL; // 头节点的指针域为空
}// 查找倒数第k个节点
int findNodeFS(Node *L, int k)
{Node *fast = L->next;Node *slow = L->next;for (int i = 0; i < k; i++){fast = fast->next;}while (fast != NULL){fast = fast->next;slow = slow->next;}printf("倒数第%d个节点值为:%d\n", k, slow->data);return 1;
}// 查找两个节点共同后缀的起始位置
Node *findIntersectionNode(Node *headA, Node *headB)
{if (headA == NULL || headB == NULL){return NULL;}Node *p = headA;int lenA = 0;int lenB = 0;// 遍历链表A,获取链表A的长度while (p != NULL){p = p->next;lenA++;}// 遍历链表B,获取链表B的长度p = headB;while (p != NULL){p = p->next;lenB++;}Node *fast; // 快指针Node *slow; // 慢指针int step;   // 两个单词之间数量的差值,可以用于快指针先走的步数if (lenA > lenB){step = lenA - lenB;fast = headA;slow = headB;}else{step = lenB - lenA;fast = headB;slow = headA;}// 让快指针先走step步for (int i = 0; i < step; i++){fast = fast->next;}// 快慢指针同步走,直到指向同一个节点退出循环while (fast != slow){fast = fast->next;slow = slow->next;}return fast;
}int main(int argc, char const *argv[])
{// 初始化链表Node *listA = InitList();Node *listB = InitList();// 获取尾节点Node *tailA = GetTail(listA);Node *tailB = GetTail(listB);// 尾插法插入数据 - A: loadtailA = InsertTail(tailA, 'l');tailA = InsertTail(tailA, 'o');tailA = InsertTail(tailA, 'a');tailA = InsertTail(tailA, 'd');// 尾插法插入数据 - B: betailB = InsertTail(tailB, 'b');tailB = InsertTail(tailB, 'e');Node *nodeI = InitListWithElem('i'); // 共享存储空间tailA = InsertTailWithNode(tailA, nodeI);tailB = InsertTailWithNode(tailB, nodeI);Node *nodeN = InitListWithElem('n');tailA = InsertTailWithNode(tailA, nodeN);tailB = InsertTailWithNode(tailB, nodeN);Node *nodeG = InitListWithElem('g');tailA = InsertTailWithNode(tailA, nodeG);tailB = InsertTailWithNode(tailB, nodeG);// 遍历链表A和链表BTraverseList(listA);TraverseList(listB);printf("%c\n", findIntersectionNode(listA, listB)->data);return 0;
}

输出:

loading
being
i请按任意键继续. . .

注意:修改的代码有几处,

元素类型改成char

typedef char ElemType; // 定义元素类型

遍历输出字符,改成%c

void TraverseList(Node *L)
{Node *p = L->next; // 从头节点的下一个节点开始遍历while (p != NULL)  // 遍历到链表末尾{printf("%c", p->data); // 输出节点的数据域,这里是%c,因为ElemType是char类型p = p->next;           // 移动到下一个节点}printf("\n"); // 换行
}

新增函数 初始化节点(带节点数据域参数)

// 初始化节点(带节点数据域参数)
Node *InitListWithElem(ElemType e)
{Node *node = (Node *)malloc(sizeof(node)); // 为节点分配内存node->data = e;                            // 节点的数据域为enode->next = NULL;                         // 节点的指针域为空return node;                               // 返回节点
}

新增函数 - 在链表尾部插入节点

 /*** @Description:单链表 - 在链表尾部插入节点* @param {Node} *tail   链表尾部节点* @param {Node} *node   要插入的节点* @return {Node *}      插入节点后的链表尾部节点*/
Node *InsertTailWithNode(Node *tail, Node *node)
{tail->next = node; // 尾节点的指针域指向要插入的节点node->next = NULL; // 要插入的节点的指针域为空return node;       // 返回新的尾节点
}

然后才是任务函数 - 查找两个节点共同后缀的起始位置


// 查找两个节点共同后缀的起始位置
Node *findIntersectionNode(Node *headA, Node *headB)
{if (headA == NULL || headB == NULL){return NULL;}Node *p = headA;int lenA = 0;int lenB = 0;// 遍历链表A,获取链表A的长度while (p != NULL){p = p->next;lenA++;}// 遍历链表B,获取链表B的长度p = headB;while (p != NULL){p = p->next;lenB++;}Node *fast; // 快指针Node *slow; // 慢指针int step;   // 两个单词之间数量的差值,可以用于快指针先走的步数if (lenA > lenB){step = lenA - lenB;fast = headA;slow = headB;}else{step = lenB - lenA;fast = headB;slow = headA;}// 让快指针先走step步for (int i = 0; i < step; i++){fast = fast->next;}// 快慢指针同步走,直到指向同一个节点退出循环while (fast != slow){fast = fast->next;slow = slow->next;}return fast;
}

最后在main函数里创造being和loading的字符条件,调用findIntersectionNode函数输出即可。


删除绝对值相等的节点

题目描述

在这里插入图片描述

解题思路

用空间换时间,用一个数组来存储已经出现过的绝对值,如果绝对值已经出现过,就删除该节点
堆内存(指针)中分配一个数组,用来存储已经出现过的绝对值
当前链表最多有n个节点(因为有n个整数)

在这里插入图片描述

代码

/*** @description: 用单链表保存n个整数,节点的结构为[data][link],且|data|<=n(n为正整数)。* 现要求设计一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的节点,* 仅保留第一次出现的节点而删除其余绝对值相等的节点。* 例如,给定单链表head如下:head-> 21 -> -15 -> 15 -> -7 -> 15* 则删除后的链表head为:head-> 21 -> -15 -> -7** 思路:用空间换时间,用一个数组来存储已经出现过的绝对值,如果绝对值已经出现过,就删除该节点*/#include <stdio.h>
#include <stdlib.h>typedef int ElemType; // 定义元素类型typedef struct node // 定义节点类型
{ElemType data;struct node *next;
} Node;/* 初始化一个单链表-造一个头节点 */
Node *InitList()
{Node *head = (Node *)malloc(sizeof(Node)); // 为头节点分配内存head->data = 0;                            // 头节点的数据域为0head->next = NULL;                         // 头节点的指针域为空return head;                               // 返回头节点
}// 初始化节点(带节点数据域参数)
Node *InitListWithElem(ElemType e)
{Node *node = (Node *)malloc(sizeof(node)); // 为节点分配内存node->data = e;                            // 节点的数据域为enode->next = NULL;                         // 节点的指针域为空return node;                               // 返回节点
}/*单链表 - 头插法*/
int InsertHead(Node *L, ElemType e)
{Node *p = (Node *)malloc(sizeof(Node)); // 创建一个新的节点p->data = e;                            // 在新节点的数据域存入数据ep->next = L->next;                      // 新节点的指针域指向头节点的下一个节点(把L的NULL复制给新节点)L->next = p;                            // 头节点的指针域指向新节点return 1;                               // 返回1表示成功
}
/* 单链表 - 遍历 */
void TraverseList(Node *L)
{Node *p = L->next; // 从头节点的下一个节点开始遍历while (p != NULL)  // 遍历到链表末尾{printf("%d ", p->data); // 输出节点的数据域,这里是%d,因为ElemType是int类型p = p->next;            // 移动到下一个节点}printf("\n"); // 换行
}/* 单链表 - 尾插法 */
// 获取尾节点地址
Node *GetTail(Node *List)
{Node *p = List;         // 从头节点开始遍历while (p->next != NULL) // 遍历到链表末尾{p = p->next; // 移动到下一个节点}return p; // 返回尾节点
}/*** @Description:单链表 - 尾插法插入数据* @param {Node} *tail   尾节点* @param {ElemType} e   插入的数据* @return {*}           返回新的尾节点*/
Node *InsertTail(Node *tail, ElemType e)
{Node *p = (Node *)malloc(sizeof(Node)); // 创建一个新的节点p->data = e;                            // 在新节点的数据域存入数据etail->next = p;                         // 尾节点的指针域指向新节点p->next = NULL;                         // 新节点的指针域为空return p;                               // 返回新的尾节点
}/*** @Description:单链表 - 在链表尾部插入节点* @param {Node} *tail   链表尾部节点* @param {Node} *node   要插入的节点* @return {Node *}      插入节点后的链表尾部节点*/
Node *InsertTailWithNode(Node *tail, Node *node)
{tail->next = node; // 尾节点的指针域指向要插入的节点node->next = NULL; // 要插入的节点的指针域为空return node;       // 返回新的尾节点
}/*** @Description:单链表 - 在指定位置插入数据* @param {Node} *L     单链表的头节点* @param {int} pos     位置* @param {ElemType} e  插入的数据* @return {*}*/
int InsertPosNode(Node *L, int pos, ElemType e)
{// 用来保存插入位置的前驱节点Node *p = L; // 从头节点开始遍历int i = 0;// 遍历链表-找到插入位置的前驱节点while (i < pos - 1) // 遍历到插入位置的前驱节点{p = p->next; // 移动到下一个节点i++;if (p == NULL) // 判断是否到达链表末尾{printf("插入位置不合法\n");return 0;}}Node *newnode = (Node *)malloc(sizeof(Node)); // 创建一个新的节点newnode->data = e;                            // 在新节点的数据域存入数据enewnode->next = p->next;                      // 新节点的指针域指向插入位置的前驱节点的下一个节点p->next = newnode;                            // 插入位置的前驱节点的指针域指向新节点return 1;
}/*** @Description:单链表 - 删除指定位置的节点* @param {Node} *L 单链表的头节点* @param {int} pos 位置* @return {*}       返回1表示成功*/
int DeletePosNode(Node *L, int pos)
{// 用来保存删除位置的前驱节点Node *p = L; // 从头节点开始遍历int i = 0;// 遍历链表-找到删除节点的前驱节点while (i < pos - 1) // 遍历到删除位置的前驱节点{p = p->next; // 移动到下一个节点i++;if (p == NULL) // 判断是否到达链表末尾{printf("删除位置不合法\n");return 0;}}if (p->next == NULL) // 判断删除位置是否合法{printf("删除位置不合法\n");return 0;}Node *q = p->next; // 保存要删除的节点的地址p->next = q->next; // 删除节点的前驱节点的指针域 指向 删除节点的下一个节点free(q);           // 释放删除节点的内存return 1; // 返回1表示成功
}int GetListLength(Node *L)
{int length = 0;Node *p = L; // 从头节点开始遍历,头节点算在内while (p != NULL){p = p->next;length++;}return length;
}void FreeList(Node *L)
{Node *p = L->next; // 从头节点的下一个节点开始遍历,头节点不需要释放Node *q = NULL;    // 用来保存下一个节点的地址,q能掌握下一个节点的地址,这是灵魂所在while (p != NULL){q = p->next; // 保存下一个节点的地址free(p);     // 释放当前节点的内存p = q;       // 移动到下一个节点}L->next = NULL; // 头节点的指针域为空
}// 查找倒数第k个节点
int findNodeFS(Node *L, int k)
{Node *fast = L->next;Node *slow = L->next;for (int i = 0; i < k; i++){fast = fast->next;}while (fast != NULL){fast = fast->next;slow = slow->next;}printf("倒数第%d个节点值为:%d\n", k, slow->data);return 1;
}// 查找两个节点共同后缀的起始位置
Node *findIntersectionNode(Node *headA, Node *headB)
{if (headA == NULL || headB == NULL){return NULL;}Node *p = headA;int lenA = 0;int lenB = 0;// 遍历链表A,获取链表A的长度while (p != NULL){p = p->next;lenA++;}// 遍历链表B,获取链表B的长度p = headB;while (p != NULL){p = p->next;lenB++;}Node *fast; // 快指针Node *slow; // 慢指针int step;   // 两个单词之间数量的差值,可以用于快指针先走的步数if (lenA > lenB){step = lenA - lenB;fast = headA;slow = headB;}else{step = lenB - lenA;fast = headB;slow = headA;}// 让快指针先走step步for (int i = 0; i < step; i++){fast = fast->next;}// 快慢指针同步走,直到指向同一个节点退出循环while (fast != slow){fast = fast->next;slow = slow->next;}return fast;
}// 函数:RemoveEqualNodes
// 功能:删除链表中与给定值相等的节点
// 参数:Node *L:链表头指针,int n:链表的长度
// 返回值:无
void RemoveEqualNodes(Node *L, int n)
{// TODO: 实现删除链表中与给定值相等的节点的功能Node *p = L;                                   // 定义一个指针p,指向链表的头节点int index;                                     // 定义一个变量index,作为数组下标使用int *q = (int *)malloc(sizeof(int) * (n + 1)); // 在堆内存中分配一个数组,用来存储已经出现过的绝对值/* 遍历数组,初始化为0 */for (int i = 0; i < n + 1; i++){*(q + i) = 0; // 初始化为0,表示没有出现过这个绝对值}while (p->next != NULL){// 获取绝对值index = abs(p->next->data); // 计算当前节点的绝对值,作为数组下标使用if (*(q + index) == 0) // 如果这个绝对值没有出现过{*(q + index) = 1; // 标记为已经出现过p = p->next;      // 移动到下一个节点}else // 如果这个绝对值已经出现过,删除当前节点{Node *tempNode = p->next; // 保存要删除的节点的地址p->next = tempNode->next; // 删除当前节点free(tempNode);           // 释放当前节点的内存}}free(q); // 释放数组的内存
}int main()
{// 初始化链表Node *list = InitList();// 获取尾节点Node *tail = GetTail(list);tail = InsertTail(tail, 21);tail = InsertTail(tail, 22);tail = InsertTail(tail, 23);tail = InsertTail(tail, -21);tail = InsertTail(tail, 10);tail = InsertTail(tail, -22);tail = InsertTail(tail, -23);TraverseList(list); // 遍历链表// 删除绝对值相等的节点RemoveEqualNodes(list, 23); // 传入链表头指针和 n个整数的n值TraverseList(list);         // 遍历链表return 0;
}

输出正确

在这里插入图片描述


在这里插入图片描述

相关文章:

【数据结构】链表应用1

链表应用 面试题 02.02.返回倒数第k个节点题目描述思路解题过程复杂度 查找相同后缀题目描述解题思路完整代码&#xff1a; 删除绝对值相等的节点题目描述解题思路代码 面试题 02.02.返回倒数第k个节点 题目描述 实现一种算法&#xff0c;找出单向链表中倒数第 k 个节点。返回…...

python gltf生成预览图

使用Python生成GLTF模型的预览图 随着3D技术的不断发展&#xff0c;GLTF&#xff08;GL Transmission Format&#xff09;逐渐成为了Web和移动应用程序中最流行的3D文件格式之一。GLTF文件不仅能以较小的体积存储复杂的3D模型&#xff0c;还支持动画、材质、光照和纹理等特性。…...

HTTP和HTTPS协议详解

HTTP和HTTPS协议详解 HTTP详解什么是http协议http协议的发展史http0.9http1.0http1.1http2.0 http协议的格式URI和URL请求request响应response http协议完整的请求与响应流程 HTTPS详解为什么使用HTTPSSSL协议HTTPS通信过程TLS协议 HTTP详解 什么是http协议 1、全称Hyper Tex…...

实战:利用百度站长平台加速网站收录

本文转自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/33.html 利用百度站长平台加速网站收录是一个实战性很强的过程&#xff0c;以下是一些具体的步骤和策略&#xff1a; 一、了解百度站长平台 百度站长平台是百度为网站管理员提供的一系列工…...

专门记录台式电脑常见问题

1、蓝屏死机&#xff0c;检查内存硬盘和cpu 2、拆内存条&#xff0c;用橡皮擦金手指 3、放主板静电&#xff0c;扣主板电池 4、系统时间不正确&#xff0c;主板电池没电 5、开机键坏了 6、电脑主机的风扇转&#xff0c;正常通电运行&#xff0c;但显示器没信号。看键盘的num键&…...

数据库系统概念第六版记录 一

1.关系型数据库 关系型数据库&#xff08;Relational Database&#xff0c;简称 RDB&#xff09;是基于关系模型的一种数据库&#xff0c;它通过表格的形式来组织和存储数据。每个表由若干行&#xff08;记录&#xff09;和列&#xff08;字段&#xff09;组成&#xff0c;数据…...

本地Ollama部署DeepSeek R1模型接入Word

目录 1.本地部署DeepSeek-R1模型 2.接入Word 3.效果演示 4.问题反馈 上一篇文章办公新利器&#xff1a;DeepSeekWord&#xff0c;让你的工作更高效-CSDN博客https://blog.csdn.net/qq_63708623/article/details/145418457?spm1001.2014.3001.5501https://blog.csdn.net/qq…...

Meta Sapiens AI论文解读:人类视觉模型基石初现,AI 未来走向何方?

一、引言 在本文中&#xff0c;我们将深入探讨 Meta AI 的一项新成果&#xff0c;该成果发表于一篇题为《Sapiens&#xff1a;人类视觉模型的基础》的研究论文中。这篇论文介绍了一系列模型&#xff0c;这些模型针对四项以人类为中心的基本任务&#xff0c;正如我们在上面的演示…...

输入类控件和多元素控件【QT】

文章目录 输入类控件QLineEdit Text EditCombo BoxSpin BoxDialSlider多元素控件QListWidget TableWidetTreeWidgetQGroupBoxTab Widget# QVBoxLayout# QHBoxLayoutQGridLayoutQFormLayout 输入类控件 QLineEdit 例如&#xff1a; 实现一个用户输入姓名 密码 电话 性别 的功能…...

一键开启/关闭deepseek

一键开启/关闭 Deepseek对应下载的模型一键开启 Deepseek&#xff0c;一键关闭Deepseek双击对应的bat&#xff0c;就可以启动https://mbd.pub/o/bread/Z56YmpZvbat 下载&#xff1a;https://mbd.pub/o/bread/Z56YmpZv 可以自己写下来&#xff0c;保存成bat文件&#xff0c;也可…...

gitea - fatal: Authentication failed

文章目录 gitea - fatal: Authentication failed概述run_gitea_on_my_pkm.bat 笔记删除windows凭证管理器中对应的url认证凭证启动gitea服务端的命令行正常用 TortoiseGit 提交代码备注END gitea - fatal: Authentication failed 概述 本地的git归档服务端使用gitea. 原来的用…...

Spring AI 智能体通过 MCP 集成本地文件数据

作者&#xff1a;刘军 Model Context Protocol&#xff08;MCP&#xff09;简介 模型上下文协议&#xff08;即 Model Context Protocol&#xff0c;MCP&#xff09; [ 1] 是一个开放协议&#xff0c;它规范了应用程序如何向大型语言模型&#xff08;LLM&#xff09;提供上下…...

音视频入门基础:RTP专题(5)——FFmpeg源码中,解析SDP的实现

一、引言 FFmpeg源码中通过ff_sdp_parse函数解析SDP。该函数定义在libavformat/rtsp.c中&#xff1a; int ff_sdp_parse(AVFormatContext *s, const char *content) {const char *p;int letter, i;char buf[SDP_MAX_SIZE], *q;SDPParseState sdp_parse_state { { 0 } }, *s1…...

MyBatis XML文件配置

目录 一、 配置连接字符串和MyBatis 二、书写持久层代码 2.1 添加Mapper接口 2.2 添加UserlnfoXMLMapper.xml 三、增删改查 3.1 、增&#xff08;Insert&#xff09; 3.2、删&#xff08;Delete) 3.3、改 (Update) 3.4、查 (Select) MyBatisXML的方式需要以下两步&am…...

【Leetcode 热题 100】1143. 最长公共子序列

问题背景 给定两个字符串 t e x t 1 text_1 text1​ 和 t e x t 2 text_2 text2​&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 0 0。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变…...

【算法】动态规划专题④ ——LCS(最长公共子序列)+ LPS(最长回文子序列) python

目录 前置知识LCS举一反三LPS 前置知识 【算法】动态规划专题③ ——二维DP python 子序列定义为&#xff1a; 不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 LCS 最长公共子序列 https://www.lanqiao.cn/problems/1189/learning/?p…...

Cesium点集中获取点的id,使用viewer.value.entities.getById报错的解决方法

错误代码&#xff1a; viewer.value.entities.getById(pickedObject.id) 报错&#xff1a; 可以正常获取movement.position但是一直出现如下报错&#xff0c;无法获得航点的id&#xff0c;通过断点定位为 viewer.value.entities.getById(pickedObject.id)导致的报错 解决方…...

360手机刷机 360手机解Bootloader 360手机ROOT

360手机刷机 360手机解Bootloader 360手机ROOT 问&#xff1a;360手机已停产&#xff0c;现在和以后&#xff0c;能刷机吗&#xff1f; 答&#xff1a;360手机&#xff0c;是肯定能刷机的 360手机资源下载网站 360手机-360手机刷机RootTwrp 360os.top 360rom.github.io 一、…...

深度探索DeepSeek-R1:AI大模型的本地应用与个人知识库构建

深度探索DeepSeek-R1&#xff1a;AI大模型的本地应用与个人知识库构建 引言 在当今这个信息爆炸的时代&#xff0c;如何高效地存储、处理和获取知识&#xff0c;已经成为每个人面临的挑战。想象一下&#xff0c;如果你能在没有互联网连接的情况下&#xff0c;构建一个属于自己…...

LabVIEW图像采集与应变场测量系统

开发了一种基于LabVIEW的图像采集与应变场测量系统&#xff0c;提供一种高精度、非接触式的测量技术&#xff0c;用于监测物体的全场位移和应变。系统整合了实时监控、数据记录和自动对焦等功能&#xff0c;适用于工程应用和科学研究。 项目背景 传统的位移和应变测量技术往往…...

解决DeepSeek服务器繁忙问题:本地部署与优化方案

deepseek服务器崩了&#xff0c;手把手教你如何在手机端部署一个VIP通道&#xff01; 引言 随着人工智能技术的快速发展&#xff0c;DeepSeek等大语言模型的应用越来越广泛。然而&#xff0c;许多用户在使用过程中遇到了服务器繁忙、响应缓慢等问题。本文将探讨如何通过本地部…...

今日AI和商界事件(2025-02-05)

今日AI领域的相关事件主要包括以下几个方面&#xff1a; 一、DeepSeek引发全球关注 性能与成本优势&#xff1a; DeepSeek推出的R1模型性能出色&#xff0c;成本较低&#xff0c;在全球AI行业引发震动。该模型在数学、代码处理等方面性能优异&#xff0c;受到广泛赞誉。 平台…...

SQL 秒变 ER 图 sql转er图

&#x1f680;SQL 秒变 ER 图&#xff0c;校园小助手神了&#xff01; 学数据库的宝子们集合&#x1f64b;‍♀️ 是不是每次碰到 SQL 转 ER 图就头皮发麻&#xff1f;看着密密麻麻的代码&#xff0c;脑子直接死机&#xff0c;好不容易理清一点头绪&#xff0c;又被复杂的表关…...

SQL server 创建DB Link 详解

在日常工作中&#xff0c;经常涉及到跨库操作&#xff0c;为使跨数据库的操作变得更加灵活高效&#xff0c;我们可以在 SQL Server 中建立数据库链接&#xff08; DB Link&#xff09;&#xff0c;实现 SQL Server 数据库与其他数据库&#xff08;如 Oracle, MySQL 等&#xff…...

25.2.5学习记录

今天主要学的是哈希表的理论知识&#xff0c;但是都是c实现&#xff0c;C语言的代码实现还没有完全搞明白。 在写题的时候&#xff0c;懵懂的学着正确代码&#xff0c;用C语言模拟实现哈希表去解题。 在哈希表的理论知识中&#xff0c;学到哈希函数&#xff0c;了解哈希冲突产…...

C# List 列表综合运用实例⁓Hypak原始数据处理编程小结

C# List 列表综合运用实例⁓Hypak原始数据处理编程小结 1、一个数组解决很麻烦引出的问题1.1、RAW 文件尾部数据如下:1.2、自定义标头 ADD 或 DEL 的数据结构如下&#xff1a; 2、程序 C# 源代码的编写和剖析2.1、使用 ref 关键字&#xff0c;通过引用将参数传递&#xff0c;以…...

不可信的搜索路径(CWE-426)

漏洞描述&#xff1a;程序使用关键资源时&#xff08;如动态链接库、执行文件、配置文件等&#xff09;没有明确的指定资源的路径&#xff0c;而是依赖操作系统去搜索资源&#xff0c;这种行为可能被攻击者利用&#xff0c;通过在搜索优先级较高的目录放置不良资源&#xff0c;…...

Unity 2D实战小游戏开发跳跳鸟 - 记录显示最高分

上一篇文章中我们实现了游戏的开始界面,在开始界面中有一个最高分数的UI,本文将接着实现记录最高分数以及在开始界面中显示最高分数的功能。 添加跳跳鸟死亡事件 要记录最高分,则需要在跳跳鸟死亡时去进行判断当前的分数是否是最高分,如果是最高分则进行记录,如果低于之前…...

openeuler 22.03 lts sp4 使用 cri-o 和 静态 pod 的方式部署 k8s-v1.32.0 高可用集群

前情提要 整篇文章会非常的长…可以选择性阅读,另外,这篇文章是自己学习使用的,用于生产,还请三思和斟酌 静态 pod 的部署方式和二进制部署的方式是差不多的,区别在于 master 组件的管理方式是 kubectl 还是 systemctl有 kubeadm 工具,为什么还要用静态 pod 的方式部署?…...

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>黄金矿工

目录 决策树&#xff1a;代码设计代码&#xff1a; 决策树&#xff1a; 代码设计 代码&#xff1a; class Solution {boolean[][] vis;int ret,m,n;public int getMaximumGold(int[][] grid) {m grid.length;n grid[0].length;vis new boolean[m][n]; for(int i 0; i <…...

SQL Server配置管理器无法连接到 WMI 提供程序

目录 第一步第二部 第一步 发现没有资源管理器 ​​​​ 在文件夹找到管理器 打开发现报这个错误 配置管理器无法连接到 WMI 提供程序第二部 https://blog.csdn.net/thb369208315/article/details/126954074...

微信小程序获取openid和其他接口同时并发请求如何保证先获取到openid

在微信小程序中,如果你需要并发请求获取 openid 和其他接口的数据,并且希望确保先获取到 openid 之后再进行后续操作,可以考虑以下几种方法: 方法一:使用 Promise 链 1, 先请求 openid:使用 Promise 来请求 openid。 2, 在获取到 openid 后再请求其他接口。 function g…...

为AI聊天工具添加一个知识系统 之87 详细设计之28 Derivation 统一建模元模型 之1

文本要点 要点 Derivation 统一建模元模型 Derivation 统一建模元模型&#xff1a;意识原型的祖传代码&#xff0c;即支撑 程序框架的 符号学中的 自然和逻辑树。 这棵树的雏形中描述了三种建模工件&#xff1a;语用钩子&#xff0c;语法糖和语义胶水。 三种工件对应的三“…...

java进阶知识点

java回收机制 浅谈java中的反射 依赖注入的简单理解 通过接口的引用和构造方法的表达&#xff0c;将一些事情整好了反过来传给需要用到的地方~ 这样做得好处&#xff1a;做到了单一职责&#xff0c;并且提高了复用性&#xff0c;解耦了之后&#xff0c;任你如何实现&#xf…...

63.视频推荐的算法|Marscode AI刷题

1.题目 问题描述 西瓜视频正在开发一个新功能&#xff0c;旨在将访问量达到80百分位数以上的视频展示在首页的推荐列表中。实现一个程序&#xff0c;计算给定数据中的80百分位数。 例如&#xff1a;假设有一个包含从1到100的整数数组&#xff0c;80百分位数的值为80&#xf…...

19.[前端开发]Day19-王者荣项目耀实战(二)

01_(掌握)王者荣耀-main-banner展示实现 完整代码 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewpor…...

Leetcode面试高频题分类刷题总结

https://zhuanlan.zhihu.com/p/349940945 以下8个门类是面试中最常考的算法与数据结构知识点。 排序类&#xff08;Sort&#xff09;&#xff1a; 基础知识&#xff1a;快速排序&#xff08;Quick Sort&#xff09;&#xff0c; 归并排序&#xff08;Merge Sort&#xff09;的…...

JPA使用@EntityGraph立即加载关联实体

在JpaRepository接口中实现自定义查询的时候&#xff0c;必然会遇到一个问题&#xff0c;通过findBy等语句查询出来的结果通常情况下不会加载到关联的实体。例如我有一个Material类&#xff0c;其中有一个属性supplier使用了多对一关联到Supplier类&#xff0c;并开启懒加载&am…...

python多版本管理工具之pyenv

pyenv 是一个用于管理多个 Python 版本的工具,允许用户在同一台机器上轻松安装、切换和隔离不同版本的 Python 解释器。它特别适合需要同时处理多个项目的开发者(例如,不同项目依赖不同 Python 版本的情况)。以下是 pyenv 的详细指南: 本文基于Ubuntu 22.04版本进行安装,…...

107,【7】buuctf web [CISCN2019 华北赛区 Day2 Web1]Hack World

这次先不进入靶场 看到红框里面的话就想先看看uuid是啥 定义与概念 UUID 是 Universally Unique Identifier 的缩写&#xff0c;即通用唯一识别码。它是一种由数字和字母组成的 128 位标识符&#xff0c;在理论上可以保证在全球范围内的唯一性。UUID 的设计目的是让分布式系…...

9. k8s二进制集群之kube-controller-manager部署

同样在部署主机上创建证书请求文件(为之后的证书生成做准备)根据上面的证书文件创建证书(结果会在当前目录下产生kube-controller-manager证书)创建kube-controller-manager服务配置文件创建kube-controller-manager服务启动文件同步kube-controller-manager证书到对应mast…...

keil 单步调试技巧

一、常见错误分析 warningerror警告错误 不影响编译过程 能够输出Hex文件 无法完成编译 不输出Hex文件 注意的是,warning的信息是要去关注的。 下面的UNCALLED SEGMENT除外 二、单步调试配置 1、在keil中添加单片机型号 本文不详细介绍,如有需要可查看这篇文章:...

[leetcode]两数之和等于target

源代码 #include <iostream> #include <list> #include <iterator> // for std::prev using namespace std; int main() { int target 9; list<int> l{ 2, 3, 4, 6, 8 }; l.sort(); // 确保列表是排序的&#xff0c;因为双指针法要求输入是…...

Go语言的转义字符

文章目录 1. Go语言的转义字符(escapechar)2. 小结和提示 1. Go语言的转义字符(escapechar) 说明:常用的转义字符有如下: \t : 表示一个制表符&#xff0c;通常使用它可以排版\n &#xff1a;换行符\\ &#xff1a;一个\\" &#xff1a;一个"\r &#xff1a;一个回…...

低代码系统-产品架构案例介绍、蓝凌(十三)

蓝凌低代码系统&#xff0c;依旧是从下到上&#xff0c;从左至右的顺序。 技术平台h/iPaas 指低层使用了哪些技术&#xff0c;例如&#xff1a;微服务架构&#xff0c;MySql数据库。个人认为&#xff0c;如果是市场的主流&#xff0c;就没必要赘述了。 新一代门户 门户设计器&a…...

【大数据技术】搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn)

搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn) jdk-8u361-linux-x64.tarhadoop-3.3.6.tar.gz注:请在阅读本篇文章前,将以上资源下载下来。 写在前面 本文主要介绍搭建完全分布式高可用集群Hadoop+MapReduce+Yarn的详细步骤。 注意: 统一约定将软件安装包存放…...

Rapidjson 实战

Rapidjson 是一款 C 的 json 库. 支持处理 json 格式的文档. 其设计风格是头文件库, 包含头文件即可使用, 小巧轻便并且性能强悍. 本文结合样例来介绍 Rapidjson 一些常见的用法. 环境要求 有如何的几种方法可以将 Rapidjson 集成到您的项目中. Vcpkg安装: 使用 vcpkg instal…...

string类OJ练习题

目录 文章目录 前言 一、反转字符串 二、反转字符串 II 三、反转字符串中的单词 III 四、验证一个字符串是否是回文 五、字符串相加&#xff08;大数加法&#xff09; 六、字符串相乘&#xff08;大数乘法&#xff09; 七、把字符串转化为整数&#xff08;atoi&#xff09; 总结…...

Python进行模型优化与调参

在数据科学与机器学习领域,模型的优化与调参是提高模型性能的重要步骤之一。模型优化可以帮助提高模型的准确性和泛化能力,而合理的调参则能够充分发挥模型的潜力。这篇教程将重点介绍几种常用的模型优化与调参方法,特别是超参数调整和正则化技术的应用。这些技术能够有效地…...

Ollama+deepseek+Docker+Open WebUI实现与AI聊天

1、下载并安装Ollama 官方网址&#xff1a;Ollama 安装好后&#xff0c;在命令行输入&#xff0c; ollama --version 返回以下信息&#xff0c;则表明安装成功&#xff0c; 2、 下载AI大模型 这里以deepseek-r1:1.5b模型为例&#xff0c; 在命令行中&#xff0c;执行&…...