数据结构算法题——链表

leetcode-2.两数之和

leetcode-2.两数之和
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){struct ListNode* head = NULL, * tail = NULL;int carry = 0;while(l1 || l2){int a = l1 ? l1->val : 0;int b = l2 ? l2->val : 0;if(!head){head = tail = malloc(sizeof(struct ListNode));tail->val = (a + b + carry) % 10;tail->next = NULL;}else{tail->next = malloc(sizeof(struct ListNode));tail->next->val = (a + b + carry) % 10;tail = tail-> next;tail->next = NULL;}carry = (a + b + carry) / 10;if(l1){l1 = l1->next;}if(l2){l2 = l2->next;}}if(carry > 0){tail->next = malloc(sizeof(struct ListNode));tail->next->val = carry;tail = tail->next;tail->next = NULL;}return head;
}

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

leetcode-19.删除链表的倒数第N个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){struct ListNode* headNode = (struct ListNode*)malloc(sizeof(struct ListNode));headNode->val = 0;headNode->next = head;struct ListNode* fast = head;struct ListNode* slow = headNode;int len = 0;while(len < n){len++;fast = fast->next;}while(fast != NULL){slow = slow->next;fast = fast->next;}slow->next = slow->next->next;struct ListNode* ret = headNode->next;free(headNode);return ret;
}

时间复杂度:O(L),其中L是链表的长度。
空间复杂度:O(1)。

leetcode-21.合并两个有序链表

leetcode-21.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

方法一:带头结点

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if(list1 == NULL) return list2;if(list2 == NULL) return list1;struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* tail = head;while(list1 != NULL && list2 != NULL){if(list1->val < list2->val){tail->next = list1;list1 = list1->next;}else{tail->next = list2;list2 = list2->next;}tail = tail->next;}if(list1 != NULL) tail->next = list1;else tail->next = list2;struct ListNode* first = head->next;free(head);return first;
}

方法二:不带头结点

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if(list1 == NULL) return list2;if(list2 == NULL) return list1;struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));if(list1->val < list2->val){head = list1;list1 = list1->next;}else{head = list2;list2 = list2->next;}struct ListNode* tail = head;while(list1 != NULL && list2 != NULL){if(list1->val < list2->val){tail->next = list1;list1 = list1->next;}else{tail->next = list2;list2 = list2->next;}tail = tail->next;}if(list1 != NULL) tail->next = list1;else tail->next = list2;return head;
}

时间复杂度:O(n + m),其中 n 和 m 分别为两个链表的长度。因为每次循环迭代中,list1 和 list2 只有一个元素会被放进合并链表中, 因此 while 循环的次数不会超过两个链表的长度之和。所有其他操作的时间复杂度都是常数级别的,因此总的时间复杂度为 O(n + m)。
空间复杂度:O(1)。我们只需要常数的空间存放若干变量。

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

leetcode-24.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

struct ListNode* swapPairs(struct ListNode* head){struct ListNode* swapList = (struct ListNode*)malloc(sizeof(struct ListNode));swapList->next = head;struct ListNode* temp = swapList;while(temp->next != NULL && temp->next->next != NULL){struct ListNode* node1 = temp->next;struct ListNode* node2 = temp->next->next;temp->next = node2;node1->next = node2->next;node2->next = node1;temp = node1;}return swapList->next;
}

时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
空间复杂度:O(1)。

leetcode-61.循环链表

leetcode-61.循环链表
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

struct ListNode* rotateRight(struct ListNode* head, int k){if(head == NULL)return NULL;struct ListNode* p = head;int n = 1;  // 用于计算链表长度while(p->next != NULL){p = p->next;n++;}p->next = head;     // head 变为循环链表int m = n - k % n;      // 计算移位后头节点的前一个节点while(m > 0){p = p-> next;m--;}head = p->next;     // 将移位后的头节点赋给 headp->next = NULL;     // 断开循环链表return head;
}

时间复杂度:O(n)。
空间复杂度:O(1)。

leetcode-82.删除排序链表中的重复元素 II

leetcode-82.删除排序链表中的重复元素 II
给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* deleteDuplicates(struct ListNode* head){if(!head){return head;}struct ListNode* h = malloc(sizeof(struct ListNode));h->next = head;struct ListNode* cur = h;while(cur->next && cur->next->next){if(cur->next->val == cur->next->next->val){int x = cur->next->val;while(cur->next && cur->next->val == x){cur->next = cur->next->next;}}else{cur = cur->next;}}return h->next;
}

时间复杂度:O(n),其中 n 是链表的长度。
空间复杂度:O(1)。

leetcode-83.删除排序链表中的重复元素

leetcode-83.删除排序链表中的重复元素
给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* deleteDuplicates(struct ListNode* head){if(!head){return head;}struct ListNode* cur = malloc(sizeof(struct ListNode));cur = head;while(cur->next){if(cur->val == cur->next->val){cur->next = cur->next->next;}else{cur = cur->next;}}return head;
}

时间复杂度:O(n),其中 n 是链表的长度。
空间复杂度:O(1)。

leetcode-86.分隔链表

leetcode-86.分隔链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* partition(struct ListNode* head, int x){struct ListNode* small = malloc(sizeof(struct ListNode));struct ListNode* smallHead = small;struct ListNode* large = malloc(sizeof(struct ListNode));struct ListNode* largeHead = large;while(head != NULL){if(head->val < x){small->next = head;small = small->next;}else{large->next = head;large = large->next;}head = head->next;}large->next = NULL;small->next = largeHead->next;return smallHead->next;
}

时间复杂度:O(n),其中 n 是原链表的长度。我们对该链表进行了一次遍历。
空间复杂度:O(1)。

leetcode-92.反转链表 II

leetcode-92.反转链表 II
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表

struct ListNode* reverseBetween(struct ListNode* head, int left, int right){struct ListNode* node = malloc(sizeof(struct ListNode));node->next = head;struct ListNode* pre = malloc(sizeof(struct ListNode));pre = node;int t = 1;while(t < left){pre = pre->next;t++;}struct ListNode* cur = pre->next;struct ListNode* l;while(t < right){l = cur->next;cur->next = cur->next->next;l->next = pre->next;pre->next = l;t++;}return node->next;
}

时间复杂度:O(n),其中 n 是链表总节点数。最多只遍历了链表一次,就完成了反转。
空间复杂度:O(1)。只使用到常数个变量。

leetcode-141.环形链表

leetcode-141.环形链表
给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

bool hasCycle(struct ListNode *head) {if(head == NULL || head->next == NULL)return false;struct ListNode* slow = head;struct ListNode* fast = head->next;while(slow != fast){if(fast == NULL || fast->next == NULL)return false;slow = slow->next;fast = fast->next->next;}return true;
}

时间复杂度:O(N),其中 N 是链表中的节点数。

  • 当链表中不存在环时,快指针将先于慢指针到达链表尾部,链表中每个节点至多被访问两次。
  • 当链表中存在环时,每一轮移动后,快慢指针的距离将减小一。而初始距离为环的长度,因此至多移动 N 轮。

空间复杂度:O(1)。我们只使用了两个指针的额外空间。

leetcode-142.环形链表 II

leetcode-142.环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* slow = head;struct ListNode* fast = head;while(fast != NULL){slow = slow->next;if(fast->next == NULL)return NULL;fast = fast->next->next;if(slow == fast){struct ListNode* ptr = head;while(ptr != slow){ptr = ptr->next;slow = slow->next;}return ptr;}}return NULL;
}

时间复杂度:O(N),其中 N 为链表中节点的数目。在最初判断快慢指针是否相遇时,slow 指针走过的距离不会超过链表的总长度;随后寻找入环点时,走过的距离也不会超过链表的总长度。因此,总的执行时间为 O(N)+O(N)=O(N)。
空间复杂度:O(1)。我们只使用了 slow,fast,ptr 三个指针。

leetcode-143.重排链表

leetcode-143.重排链表
在这里插入图片描述

// 找中间节点
struct ListNode* middleNode(struct ListNode* head)
{struct ListNode* slow = head;struct ListNode* fast = head;while(fast->next != NULL && fast->next->next != NULL){slow = slow->next;fast = fast->next->next;}return slow;
}// 反转链表
struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* prev = NULL;struct ListNode* nxt = head;while(nxt != NULL){struct ListNode* nxtTmp = nxt->next;nxt->next = prev;prev = nxt;nxt = nxtTmp;}return prev;
}// 合并链表
void mergeList(struct ListNode* l1, struct ListNode* l2)
{struct ListNode* l1_tmp;struct ListNode* l2_tmp;while(l1 != NULL && l2 != NULL){l1_tmp = l1->next;l2_tmp = l2->next;l1->next = l2;l1 = l1_tmp;l2->next = l1;l2 = l2_tmp;}
}void reorderList(struct ListNode* head){if(head == NULL)return ;struct ListNode* mid = middleNode(head);struct ListNode* left = head;struct ListNode* right = mid->next;mid->next = NULL;right = reverseList(right);mergeList(left, right);
}

时间复杂度:O(N),其中 N 是链表中的节点数。
空间复杂度:O(1)。

leetcode-147.对链表进行插入排序

leetcode-147.对链表进行插入排序
给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。

插入排序 算法的步骤:

插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。

对链表进行插入排序。

struct ListNode* insertionSortList(struct ListNode* head){if(head == NULL){return head;}  struct ListNode* dummyHead = malloc(sizeof(struct ListNode));dummyHead->val = 0;dummyHead->next = head;struct ListNode* lastSorted = head;struct ListNode* curr = head->next;while(curr != NULL){if(lastSorted->val <= curr->val){lastSorted = lastSorted->next;}else{struct ListNode* prev = dummyHead;while(prev->next->val <= curr->val){prev = prev->next;}lastSorted->next = curr->next;curr->next = prev->next;prev->next = curr;}curr = lastSorted->next;}return dummyHead->next;
}

时间复杂度: O(n2),其中 n 是链表的长度。
空间复杂度:O(1)。

leetcode-160.相交链表

leetcode-160.相交链表
在这里插入图片描述

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {if(headA == NULL || headB == NULL){return NULL;}struct ListNode* la = headA;struct ListNode* lb = headB;while(la != lb){la = la == NULL ? headB : la->next;lb = lb == NULL ? headA : lb->next;}return la;
}

若相交,链表A: a+c, 链表B : b+c,a+c+b+c = b+c+a+c 。则会在公共处c起点相遇。
若不相交,a+b = b+a 。因此相遇处是NULL。

时间复杂度:O(m+n),其中 m 和 n 是分别是链表 headA 和 headB 的长度。两个指针同时遍历两个链表,每个指针遍历两个链表各一次。
空间复杂度:O(1)。

leetcode-203.移出链表元素

leetcode-203.移出链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

struct ListNode* removeElements(struct ListNode* head, int val){if(head == NULL){return NULL;}struct ListNode* node = malloc(sizeof(struct ListNode));node->next = head;struct ListNode* pre = node;while(pre->next != NULL){if(pre->next->val == val){pre->next = pre->next->next;}else{pre = pre->next; }}return node->next;
}

时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
空间复杂度:O(1)。

leetcode-206.反转链表

leetcode-206.反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

struct ListNode* reverseList(struct ListNode* head){struct ListNode* node1 = NULL;struct ListNode* node2 = head;while(node2 != NULL){struct ListNode* nxt = node2->next;node2->next = node1;node1 = node2;node2 = nxt;}return node1;
}

时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
空间复杂度:O(1)。

leetcode-234.回文链表

leetcode-234.回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* prev = NULL;struct ListNode* curr = head;while(curr !=  NULL){struct ListNode* nextTemp = curr->next;curr->next = prev;prev = curr;curr = nextTemp;}return prev;
}struct ListNode* endOfFirstHalf(struct ListNode* head)
{struct ListNode* fast = head;struct ListNode* slow = head;while(fast->next != NULL && fast->next->next != NULL){fast = fast->next->next;slow = slow->next;}return slow;
}bool isPalindrome(struct ListNode* head){if(head == NULL){return true;}// 找到前半部分链表的尾结点并反转后半部分链表struct ListNode* firstHalfEnd = endOfFirstHalf(head);struct ListNode* secondHalfStart = reverseList(firstHalfEnd->next);// 判断是否回文struct ListNode* p1 = head;struct ListNode* p2 = secondHalfStart;bool res = true;while(res && p2 != NULL){if(p1->val != p2->val){res = false;}p1 = p1->next;p2 = p2->next;}// 还原链表并返回结果firstHalfEnd->next = reverseList(secondHalfStart);return res;
}

时间复杂度:O(n),其中 n 指的是链表的大小。
空间复杂度:O(1)。我们只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)。

leetcode-237.删除链表中的节点

leetcode-237.删除链表中的节点
有一个单链表的 head,我们想删除它其中的一个节点 node。

给你一个需要删除的节点 node 。你将 无法访问 第一个节点 head。

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

给定节点的值不应该存在于链表中。
链表中的节点数应该减少 1。
node 前面的所有值顺序相同。
node 后面的所有值顺序相同。

void deleteNode(struct ListNode* node) {node->val = node->next->val;node->next = node->next->next;
}

时间复杂度:O(1)。
空间复杂度:O(1)。

leetcode-328.奇偶链表

leetcode-328.奇偶链表
给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

struct ListNode* oddEvenList(struct ListNode* head){if(head == NULL){return NULL;}struct ListNode* evenhead = head->next;struct ListNode* odd = head;struct ListNode* even = evenhead;while(even != NULL && even->next != NULL){odd->next = even->next;odd = odd->next;even->next = odd->next;even = even->next;}odd->next = evenhead;return head;
}

时间复杂度:O(n),其中 n 是链表的节点数。需要遍历链表中的每个节点,并更新指针。
空间复杂度:O(1)。只需要维护有限的指针。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/14452.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux调优–I/O 调度器

Linux 的 I/O 调度器是一个以块式 I/O 访问存储卷的进程&#xff0c;有时也叫磁盘调度器。Linux I/O 调度器的工作机制是控制块设备的请求队列&#xff1a;确定队列中哪些 I/O 的优先级更高以及何时下发 I/O 到块设备&#xff0c;以此来减少磁盘寻道时间&#xff0c;从而提高系…

【PCIE】hot-reset和link disable

Hot reset 规则 如果上游伪端口&#xff08;Pseudo Port&#xff09;的任何一个通道连续接收到两个带有热复位位设置为1b、禁用链路位和回环位设置为0b的TS1有序集合&#xff0c;并且两个伪端口上的任何一个通道&#xff08;接收到TS1有序集合&#xff09;要么收到EIOS&#xf…

通俗易懂生成对抗网络GAN原理(二)

生成对抗网络&#xff08;Generative Adversarial Network, GAN&#xff09;的原理 学习李宏毅机器学习课程总结。 前面学习了GAN的直观的介绍&#xff0c;现在学习GAN的基本理论。现在我们来学习GAN背后的理论。 引言 假设x是一张图片&#xff08;一个高维向量&#xff09;…

DevOps系列文章 之 SnakeYAML解析与序列化YAML

1、简述 如何使用SnakeYAML库将YAML文档转换为Java对象&#xff0c;以及JAVA对象如何序列化为YAML文档。 在DevOps平台系统中是基础的能力支持&#xff0c;不管是spring boot 的配置还是K8S 资源清单yaml 2、项目设置 要在项目中使用SnakeYAML&#xff0c;需要添加Maven依赖…

百度网盘删除“我的应用数据”文件夹

方法一&#xff1a;电脑端 工具链接&#xff0c; BaiduPCS-Go-3.6.8-windows-86.zip - 蓝奏云 电脑端下载解压运行&#xff0c;弹出浏览器窗口和命令行&#xff0c;在浏览器中输入百度网盘账号密码&#xff0c;登录。 之后会需要输入验证码&#xff0c;之后使用手机号或者邮…

恒生电子探路金融大模型

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 近日&#xff0c;恒生电子和旗下子公司恒生聚源正式发布基于大语言模型技术打造的数智金融新品&#xff1a;金融智能助手光子和全新升级的智能投研平台WarrenQ。此外&#xff0c;恒生电子金融行业大模型LightGPT也首次对外亮…

Ctfshow web入门 nodejs篇 web334-web344

CTFshow NodeJs web334 前言&#xff1a;做原型链污染&#xff0c;入门的话个人建议先看看P神的文章&#xff0c;只看前四部分就行了。 深入理解 JavaScript Prototype 污染攻击 | 离别歌 (leavesongs.com) 然后也得有一点js基础&#xff0c;不用太多&#xff0c;要不然看起…

web安全php基础_搭建php环境

首先打开phpstudy的网站栏点击创建网站&#xff0c;新建一个网站&#xff08;域名随便输反正是局域网&#xff09;然后点击确认 如下&#xff0c;网站便创建好了 打开浏览器输入刚刚创建网站时输入的域名&#xff0c;即可看见我们的网站 然后网站好了&#xff0c;就可以新建项…

Vue和React的区别?

目录 共同点 1. 数据驱动视图 2. 组件化 3. Virtual DOM 不同点 1. 核心思想不同 2. 组件写法差异 3. diff算法不同 4. 响应式原理不同 5. 其他不同点 首先找到 Vue 和 React 的共性&#xff0c;它们被用于解决什么问题&#xff0c; 然后再挖掘各自独特的个性、设计原…

基于WebSocket的简易聊天室的基本实现梳理

一&#xff0c;前言 目前在很多网站为了实现推送技术所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔&#xff08;如每1秒&#xff09;&#xff0c;由浏览器对服务器发出HTTP请求&#xff0c;然后由服务器返回最新的数据给客户端的浏览器。HTTP 协议是一种无状态的、无连…

【Rust】所有权

文章目录 所有权stack与heap所有权存在的原因所有权规则变量作用域String类型内存和分配变量与数据交互的方式1.Move2.Clone3.Copy 所有权与函数返回值与作用域引用借用可变引用悬空引用Dangling References引用的规则切片字符串切片将字符串切片作为参数传递其他类型的切片 所…

CentOS Linux的替代品(六)_BigCloud Enterprise Linux R8 U2 基础安装教程

文章目录 CentOS Linux的替代品&#xff08;六&#xff09;_BigCloud Enterprise Linux R8 U2 基础安装教程一、BC-Linux简介二、BigCloud Enterprise Linux R8 U2 基础安装2.1 下载地址2.2 安装过程 三、简单使用3.1 关闭selinux3.1.1 临时关闭selinux3.1.2 永久关闭selinux 3…