数组和链表OJ题

   leetcode用编译器调试的技巧

 数组和链表练习题

leetcode/reverse_Link/main.c · Hera_Yc/bit_C_学习 - 码云 - 开源中国

1、移除元素

​​​​​​27. 移除元素 - 力扣(LeetCode)

int removeElement(int* nums, int numsSize, int val)
{int src = 0, dst = 0;//用src替换dstwhile (src < numsSize){if (nums[src] != val){nums[dst] = nums[src];src++;dst++;}else{++src;}}return dst;
}

2、删除排序数组中的重复项 

26. 删除有序数组中的重复项 - 力扣(LeetCode)

int removeDuplicates(int* nums, int numsSize) 
{int prev = 0;int cur = prev+1;int dst = 0;while (cur < numsSize){if (nums[prev] == nums[cur]){prev++;cur++;}else{nums[dst] = nums[prev];dst++;prev++;cur++;}}nums[dst] = nums[prev];dst++;return dst;}

3、 数组形式的加法

989. 数组形式的整数加法 - 力扣(LeetCode)
 

//数组形式的加法
//大数的加法
int* addToArrayForm(int* num, int numSize, int k,int* returnSize)
{int KSize = 0;//求出K的位数int Num = k;while (Num){Num /= 10;KSize++;}//比较K的位数和数组的长度谁大?最终结果的位数:一定是大的那位+1(或者就是最大的那一位)//保险起见:我们用大一位开辟内存//calloc初始化一下int* retArr = (int*)calloc((KSize > numSize ? KSize + 1 : numSize + 1),sizeof(int));int tmp = 0;int cur = numSize - 1;int flag = 0;//进位//对于retArr可以倒着放,也可以正着放,然后逆置int reti = 0;int len = KSize > numSize ? KSize : numSize;while (len--){int tmpn = 0;if (cur >= 0){tmpn = num[cur];}tmp = k % 10;k = k / 10;retArr[reti] = tmp + tmpn + flag;//完成每一位的计算if (retArr[reti] >= 10){retArr[reti] = retArr[reti] - 10;flag = 1;//如果进位了}else{flag = 0;}cur--;reti++;}//观察进位符号是否为1:if (flag == 1){retArr[reti] = 1;//首位reti++;}//逆置int left = 0;int right = reti - 1;while (left < right){int tmp = retArr[left];retArr[left] = retArr[right];retArr[right] = tmp;left++;right--;}*returnSize = reti;return retArr;
}int main()
{int arr[4] = { 3,4 };int k = 1200;//1334int size = 0;int* p = NULL;p=addToArrayForm(arr, 2, k,&size);int i = 0;for (i = 0; i < 4; i++){printf("%d ", p[i]);}
}
4、反转链表

反转链表(逆置单链表),可以说是链表最关键的操作之一。(两种方法)。

206. 反转链表 - 力扣(LeetCode)

 //三指针逆方向
struct ListNode* reverseList(struct ListNode* head) 
{if(head==NULL||head->next==NULL){return head;}else{struct ListNode* cur=head;struct ListNode* prev=NULL;while(cur!=NULL){struct ListNode* tmp=cur->next;cur->next=prev;prev=cur;cur=tmp;}return prev;}
}//头插法
//头插创建新链表
//取cur头插到以newhead为头的新链表中
struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* newhead = NULL; //新链表的头结点struct ListNode* cur = head;struct ListNode* next = NULL;while (cur != NULL){next = cur->next;   //保存cur的下一个结点cur->next = newhead;  //头插:把cur看作待插入的新结点newhead = cur;cur = next;}return newhead;
}//头插更容易理解
5、删除所有给定值的结点

203. 移除链表元素 - 力扣(LeetCode)

struct ListNode* removeElements(struct ListNode* head, int val) 
{struct ListNode* prev=NULL;struct ListNode* cur=head;struct ListNode* next=NULL;while(cur){if(cur->val==val){if(cur==head){head=cur->next;free(cur);cur=head;}else{prev->next=cur->next;free(cur);cur=prev->next;}}else {prev=cur;cur=cur->next;}}return head;
}
6、 链表的中间结点

链表中的双指针问题:快慢指针

对于一个单链表来说:

  1. 快指针每次走两步。
  2. 慢指针每次走一步。
  3. 当快指针走到时,慢指针恰好在链表的中间。

这里对结点个数不同的链表,快指针有所差异(所指向的的不同)。

876. 链表的中间结点 - 力扣(LeetCode)

struct ListNode* middleNode(struct ListNode* head) {if (head->next == NULL) {return head;} else {struct ListNode* cur = head;int count = 0;while (cur != NULL) {count++;cur = cur->next;}count = count / 2;cur = head;while (count) {cur = cur->next;count--;}return cur;}
}//追加:要求只能遍历链表一次
struct ListNode* middleNode(struct ListNode* head) {struct ListNode* slow = head;struct ListNode* fast = head;while (fast != NULL && fast->next != NULL) {slow = slow->next;fast = fast->next->next;}return slow;
}

7、输入一个链表,输出该链表中倒数第k个结点(双指针变形)。

struct ListNode* func(struct ListNode* head, int k){struct ListNode* slow = head;struct ListNode* fast = head;while (k--&&fast){    //k有可能大于链表的长度fast = fast->next;}if (fast == NULL) return NULL;while (fast){slow = slow->next;fast = fast->next;}return slow;}
8、合并有序链表

21. 合并两个有序链表 - 力扣(LeetCode)

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{// 取小节点下来尾插if (list1 == NULL && list2 == NULL)return NULL;if (list1 == NULL)return list2;if (list2 == NULL)return list1;struct ListNode* head = NULL;struct ListNode* tail = NULL;if (list1->val < list2->val){head = tail = list1;list1 = list1->next;}else{head = tail = list2;list2 = list2->next;}//取小的尾插 while (list1 && list2){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 = list2;}if (list2 == NULL){tail->next = list1;}return head;}//方法二:哨兵位
struct ListNode* mergeTwoLists2(struct ListNode* list1, struct ListNode* list2) {//带头结点的链表(哨兵位)if (list1 == NULL && list2 == NULL)return NULL;if (list1 == NULL)return list2;if (list2 == NULL)return list1;struct ListNode* head = NULL;struct ListNode* tail = NULL;//带哨兵位的头结点,不存储有效数据,主要是方便尾插head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));//取小的尾插 while (list1 && list2){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 = list2;}if (list2 == NULL){tail->next = list1;}struct ListNode* realhead = head->next;free(head);head = NULL;return realhead;
}

   哨兵位:head = tail = (struct ListNode*)malloc(sizeof(struct ListNode)),这里的head就是哨兵,不存储任何数据,只是在尾插时不需要对list进行判断。哨兵位对尾插来说更加方便,但在绝大多数的oj题中,链表一般是不带哨兵位的,第一个头结点存储的有数据。

 9、链表分割

链表分割_牛客题霸_牛客网(双哨兵位尾插链表)

这里的maxtail不置空会产生环.

struct ListNode* partition(struct ListNode* phead, int x)
{// write code here//把pHead的结点拿出来,分两个尾插://可以尾插,亦可以头插然后反转//小于x插一次,大于x的插一次//最后整合两个链表,释放哨兵//1.空链表//if(phead==NULL)return NULL;//2.只有一个结点//if(phead->next==NULL)return phead;//1和2合并if (phead == NULL || phead->next == NULL)return phead;//3.有1个以上的结点//开辟两个哨兵struct ListNode* minhead = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* maxhead = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* cur = phead;struct ListNode* mintail = minhead;struct ListNode* maxtail = maxhead;//初始化:防止内存错误minhead->next = NULL;maxhead->next = NULL;while (cur){/*链表在这里构成环了,导致的死循环*/if (cur->val < x){mintail->next = cur;mintail = mintail->next;}else{maxtail->next = cur;maxtail = maxtail->next;}cur = cur->next;}mintail->next = maxhead->next;maxtail->next = NULL;//防止环的生成struct ListNode* realhead = minhead->next;free(minhead);minhead = NULL;free(maxhead);maxhead = NULL;return realhead;
}
10、回文链表

链表的回文结构_牛客题霸_牛客网(回文链表=链表逆置+链表的中间结点)

struct ListNode* reverseList(struct ListNode* head) {struct ListNode* newhead = NULL;  //新链表的头结点struct ListNode* cur = head;struct ListNode* next = NULL;while (cur != NULL) {next = cur->next;   //保存cur的下一个结点cur->next = newhead;  //头插:把cur看作待插入的新结点newhead = cur;cur = next;}return newhead;}//头插更容易理解bool chkPalindrome(ListNode* A) {// write code hereListNode* fast = A;ListNode* slow = A;ListNode* prev = NULL;while (fast && fast->next) {prev = slow;slow = slow->next;fast = fast->next->next;}//利用快慢指针找到那个中间结点prev->next = NULL;//分割前后两个链表slow = reverseList(slow);//反转后一半链表//逐一比较while (A) {if (A->val != slow->val) {return false;} else {A = A->next;slow = slow->next;}}return true;
}
11、相交链表的公共节点

160. 相交链表 - 力扣(LeetCode)

#include <math.h>struct ListNode* getIntersectionNode(struct ListNode* headA,struct ListNode* headB) {// 用相交结点的地址去比// 不能用结点的值去比,因为不同的结点可以存相同的值struct ListNode* curA = headA;struct ListNode* curB = headB;//这里用第二种思路:用两个链表的差值int la = 0;int lb = 0;while (curA) {la++;curA = curA->next;}//求链表A的长度while (curB) {lb++;curB = curB->next;}//求链表B的长度struct ListNode* longList = headA;struct ListNode* shortList = headB;if (lb > la) {longList = headB;shortList = headA;}int gap = abs(la - lb);//求两链表的长度差while (gap--) {        //让长的链表先走gap步longList = longList->next;}//这步操作的结果使:longList和shortList距离链表的末尾一样近while (longList) {if (longList == shortList)//比较的只能是地址,不能是值,即使两个结点值相同,也有可能不是同一个结点return longList;longList = longList->next;shortList = shortList->next;}return NULL;}

12、环形链表 i

141. 环形链表 - 力扣(LeetCode)(快慢指针)

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

 13、环形链表ii

142. 环形链表 II - 力扣(LeetCode)

这里有个很难理解的方法:待补充……

14、复杂链表的复制

138. 随机链表的复制 - 力扣(LeetCode)

struct Node* copyRandomList(struct Node* head)
{if (head == NULL)return NULL;struct Node* cur = head;//1.将拷贝结点链接在原结点的后面while (cur){//构造拷贝结点struct Node* copy = (struct Node*)malloc(sizeof(struct Node));copy->next = NULL;copy->random = NULL;copy->val = cur->val;copy->next = cur->next;cur->next = copy;cur = copy->next;}//2.处理拷贝结点的随机指针random/**这里有个较难理解的点:* 1.对于拷贝结copy点来说:它的random指针指向的必须是拷贝结点.* 2.对于原结点cur来说:它的random指针指向的是原结点* 3.cur->random:是cur随机指针指向的原结点* 4.对于任何一个原结点来说:它后面的结点就是自己的拷贝结点* 因此:* 5. copy->random = cur->random->next*/cur = head;while (cur){struct Node* copy = cur->next;if (cur->random != NULL)copy->random = cur->random->next;elsecopy->random = NULL;cur = copy->next;}//3.拆解出拷贝链表cur = head;struct Node* copyHead = head->next;while (cur){struct Node* copy = cur->next;struct Node* next = copy->next;cur->next = next;if (next != NULL)copy->next = next->next;elsecopy->next = NULL;cur = next;}return copyHead;
}
//leetcode这道题的C底层有错误,不能通过,只能用C++来实现

15、 对链表进行插入排序

147. 对链表进行插入排序 - 力扣(LeetCode)(需要画图详解)

struct ListNode* insertionSortList(struct ListNode* head) {// struct ListNode* phead=(struct ListNode*)malloc(sizeof(struct ListNode));if (head == NULL || head->next == NULL)return head;struct ListNode* sorthead = head;struct ListNode* cur = head->next;sorthead->next = NULL;// sorthead做头结点,不断取结点插入sorthead中,不断头插/尾插/中间插入while (cur) {struct ListNode* next = cur->next;// 把cur插入到sorthead中,并且保持链表有序if (cur->val <= sorthead->val) {// 头插cur->next = sorthead;sorthead = cur;} else {// 中间或尾插struct ListNode* sortprev = sorthead;struct ListNode* sortcur = sortprev->next;while (sortcur) {if (sortcur->val >= cur->val) {sortprev->next = cur;cur->next = sortcur;break;} else {sortprev = sortcur;sortcur = sortcur->next;}}if (sortcur == NULL) {sortprev->next = cur;cur->next = NULL;}}cur = next;}return sorthead;
}
//取结点往sorthead插入
16、删除链表重读元素

82. 删除排序链表中的重复元素 II - 力扣(LeetCode)

struct ListNode* deleteDuplicates(struct ListNode* head) {if (head == NULL || head->next == NULL)return head;struct ListNode* prev = NULL;struct ListNode* cur = head;struct ListNode* next = cur->next;while (next) {if (cur->val != next->val) {prev = cur;cur = next;next = next->next;} else {while (next != NULL && cur->val == next->val) {next = next->next;}// 不free掉这些结点也不会报错if (prev != NULL) {prev->next = next;} else {head = next;}// 释放while (cur != next) {struct ListNode* del = cur;cur = cur->next;free(del);}if (next != NULL)next = next->next;}}return head;
}//这道题对链表的边界有很深的考察

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

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

相关文章

Scala—数组(不可变数组Array、可变数组ArrayBuffer)用法详解

Scala集合概述-链接 大家可以点击上方链接&#xff0c;先对Scala的集合有一个整体的概念&#x1f923;&#x1f923;&#x1f923; 在 Scala 中&#xff0c;数组是一种特殊的集合类型&#xff0c;可以是可变的也可以是不可变的。 1. 不可变数组 在 Scala 中&#xff0c;不可变…

Kylin Server V10 下 Nacos 集群部署

集群部署架构图 端口 与主端口的偏移量 描述 8848 0 主端口,客户端、控制台及

摄像头原始数据读取——V4L2(userptr模式,V4L2_MEMORY_USERPTR)

摄像头原始数据读取——V4L2(userptr模式,V4L2_MEMORY_USERPTR) 用户指针方式允许用户空间的应用程序分配内存&#xff0c;并将内存地址传递给内核中的驱动程序。驱动程序直接将数据填充到用户空间的内存中&#xff0c;从而避免了数据的拷贝过程。 流程&#xff1a; 通过VIDI…

亚马逊开发视频人工智能模型,The Information 报道

根据《The Information》周三的报道&#xff0c;电子商务巨头亚马逊&#xff08;AMZN&#xff09;已开发出一种新的生成式人工智能&#xff08;AI&#xff09;&#xff0c;不仅能处理文本&#xff0c;还能处理图片和视频&#xff0c;从而减少对人工智能初创公司Anthropic的依赖…

一次完整的CNAS软件测试实验室内部审核流程

内部审核是软件测试实验室管理体系重的重要部分&#xff0c;通过内部审核可以为有效的管理评审和纠正、预防措施提供信息&#xff0c;以验证组织的管理体系是否持续的满足规定的要求并且正在运行。 内部审核需要依据文件化的程序&#xff0c;每年至少实施一次&#xff0c;软件…

Matlab数字信号处理——音频信号处理与分析GUI

1.实现内容 实现功能有回响、变声、倒放、变速、音量调整、加噪、设计 FIR和 IR 滤波器实现去噪功能(高通低通带通带阻)&#xff0c;并且在时域波形图和频域波形展示变化。滤波器包括各种参数的选择、滤波器结构和类型的选择等。同时GUI上还包含打开、播放、保存、退出功能。 …

pcb线宽与电流

三十年一路高歌猛进的中国经济&#xff0c; 中国经历了几个三十年&#xff1f; 第一个三十年&#xff1a;以计划为导向。 第二个三十年&#xff1a;以经济为导向。 现在&#xff0c;第三个三十年呢&#xff1f; 应该是以可持续发展为导向。 传统企业摇摇欲坠&#xff0c; 新兴企…

redis命令 及 redis 常见的数据结构

文章目录 一. 核心命令1. set2. get 二. 全局命令1. keys2. exists3. del4. expire5. ttl6. type 三. redis 常见的数据结构 一. 核心命令 1. set set key value key 和 value 都是string类型的 对于key value, 不需要加上引号, 就是表示字符串类型, 加上也可以 redis中, 不…

跨平台应用开发框架(4)----Qt(系统篇)

目录 1.Qt事件 1.事件来源 2.事件处理 3.按键事件 1.组合按键 4.鼠标事件 1.鼠标单击事件 2.鼠标释放事件 3.鼠标双击事件 4.鼠标移动事件 5.滚轮事件 5.定时器 1.QTimerEvent类 2.QTimer 类 3.获取系统日期及时间 6.事件分发器 7.事件过滤器 2.Qt文件 1.输入…

uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?

在uniapp(App端)中实现自定义弹框&#xff0c;可以通过创建一个透明页面来实现。点击进入当前页面时&#xff0c;页面背景会变透明&#xff0c;用户可以根据自己的需求进行自定义&#xff0c;最终效果类似于弹框。 遇到问题&#xff1a;当打开弹窗(进入弹窗页面)就会触发当前页…

DM达梦管理工具拖出空白区块,无法关闭

1. 出现问题&#xff1a;DM达梦管理工具拖出空白区块&#xff0c;无法关闭。 2. 解决方法 新建查询页&#xff0c;把查询页拖到空白区块里&#xff0c;完全覆盖空白区块。之后空白区块会变成查询页&#xff0c;右上角会出现叉号&#xff0c;点击叉号关闭就行。 3. 后记 达梦…

DevExpress的web Dashboard应用

本文旨在从零开始创建一个包含dashboard的应用 一、前期准备 1、语言&#xff1a;C# 2、软件&#xff1a;Visual Studio 2019 3、框架&#xff1a;DevExpress19.2(付费)、ASP.NET(Web) 4、组件&#xff1a;dashboard 二、创建ASP.NET Web窗体仪表板应用程序 1、创建一个空的w…

【vue-router】Vue-router如何实现路由懒加载

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

go语言切片

切片 切片是一种数据结构&#xff0c;这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的&#xff0c;可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的…

2024年一级建造师考试成绩,即将公布!

一级建造师考试成绩一般在考试结束后3个月左右的时间公布&#xff01; 根据官方通知&#xff0c;重庆、江苏、青海、江西、云南、湖南、福建、北京、山西、黑龙江等地在今年一建报名通知里提到&#xff1a;2024年一级建造师考试成绩预计于2024年12月上旬公布。考生可在这个时间…

基于Matlab的图像去噪算法仿真

中值滤波的仿真 本节选用中值滤波法对含有高斯噪声和椒盐噪声的图像进行去噪&#xff0c;并用Matlab软件仿真。 &#xff08;1&#xff09;给图像加入均值为0&#xff0c;方差为0.02的高斯噪声&#xff0c;分别选择33模板、55模板和77模板进行去噪 Matlab部分代码&#xff1…

交通流量预测:基于交通流量数据建立模型

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

嵌入式QT学习第4天:Qt 信号与槽

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本章思维导图如下&#xff1a; 不使用 Qt Designer 的方式进行开发&#xff0c;用代码绘界面&#xff0c;可以锻炼我们的布局能力&#xff0c;和代码逻辑能力&#x…

多线程+线程池

普通线程的创建 三种创建方式实例&#xff1a; 多线程本质上是毫无关系的&#xff0c;执行顺序是不可预知的&#xff0c;但是由于callable方式创建的对象有返回值所以主函数在执行的时候&#xff0c;需要等待返回值回来才能继续执行其他线程&#xff0c;所以在这种状态下是…

mac访达打开终端

选择文件夹打开 选中文件夹&#xff0c;然后右键即可&#xff1a; 在当前文件夹打开 在访达的当前文件夹长按option键 左下角出现当前文件夹路径 右键即可打开终端