顺序表、链表相关OJ题(2)

创作不易,友友们给个三连吧!!

一、旋转数组(力扣)

经典算法OJ题:旋转数组

思路1:每次挪动1位,右旋k次

时间复杂度:o(N^2)       

右旋最好情况:k是n的倍数,相当于不右旋,此时为o(1)

右旋最坏情况:k%n==n-1,此时为o(N^2)

空间复杂度:o(1)

void rotate(int* nums, int numsSize, int k) 
{k%=numsSize;while(k){int temp=nums[numsSize-1];//从后往前挪 for(int i=numsSize-1;i>0;i--){nums[i]=nums[i-1];//最后一个是nums[1]=num[0]}nums[0]=temp;k--;//旋转一次就减一次}
}

注:这是常规思路,但是由于空间复杂度太高,数组个数特别多的时候,在力扣运行的时候超出了时间限制!

思路2:创建一个和nums一样长度的新数组,将nums数组的后k个元素,先按顺序放进新数组里,然后剩下前面的n-k个元素,再按顺序放进新数组,最后再将新数组的数据拷贝到nums中

时间复杂度:o(N)

空间复杂度:o(N)

void rotate(int* nums, int numsSize, int k) 
{k%=numsSize;int arr[numsSize];//vs不支持变长数组,但是牛客支持,如果是vs只能使用动态数组。memcpy(arr,nums+numsSize-k,sizeof(int)*k);//nums的后k个按顺序拷贝到新数组的前面memcpy(arr+k,nums,sizeof(int)*(numsSize-k));//nums的前n-k个按顺序拷贝到新数组的后面memcpy(nums,arr,sizeof(int)*numsSize);//新数组完全拷贝到nums数组中
}

思路3:前n-k个元素逆置,后k个元素逆置,再整体逆置

时间复杂度:o(N)

空间复杂度:o(1)

void reverse (int *arr,int left,int right)//实现逆序函数
{int temp=0;while(left<right){temp=arr[left];arr[left]=arr[right];arr[right]=temp;left++;right--;}
}
void rotate(int* nums, int numsSize, int k) 
{k%=numsSize;reverse(nums,0,numsSize-k-1);//前n-k个元素逆序reverse(nums,numsSize-k,numsSize-1);//后k个逆序reverse(nums,0,numsSize-1);//完全逆序
}

二、消失的数字(力扣)

经典算法OJ题:消失的数字

思路1:先进行排序,如果后一个不等于前一个+1,就可以找到消失的数据,但是目前掌握的排序中,冒泡排序的时间复杂度是o(N^2),而qsort的时间复杂度是o(logN+N),均不符合题意,这里不做考虑!

思路2:让0和0-numsSize的所有数都异或一遍,再和数组中的所有元素异或一边,最后得到的结果就是消失的数(利用了a^a=0,a^0=a的结论)

时间复杂度:o(N)

空间复杂度:o(1)

int missingNumber(int* nums, int numsSize)
{
int x=0;
for(int i=0;i<numsSize;i++)
{x^=i;x^=nums[i];
}
x^=numsSize;//还多了一个数
return x;
}

思路3:0-numsSize的所有数相加,然后减去数组中的所有元素之和,得到的就是消失的数字。

时间复杂度:o(N)

空间复杂度:o(1)

int missingNumber(int* nums, int numsSize)
{int sum=0;//记录
for(int i=0;i<numsSize;i++)
{sum+=i;sum-=nums[i];
}
sum+=numsSize;
return sum;
}

三、链表中倒数第k个结点(牛客)

经典算法OJ题:链表中倒数第k个结点

思路1:第一次循环计算结点的个数count,然后求倒数第k个就是正数的第count-k个结点

空间复杂度:o(N)

时间复杂度:o(1)

 typedef struct ListNode ListNode;
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ){
ListNode* pcur= pListHead;
int count=0;//统计结点
while(pcur)
{pcur=pcur->next;count++;
}
if(count<k)
return NULL;//考虑链表为NULL,以及k大于链表结点数
pcur= pListHead;
for(int i=0;i<count-k;i++)
pcur=pcur->next;
return pcur;
}

思路2:(快慢指针)fast指针先走k步,然后fast和slow同时走,始终保持k的距离,当fast走到NULL的时候,slow对应的恰好就是倒数第k个结点

空间复杂度:o(N)

时间复杂度:o(1)

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ){
struct ListNode*fast=pListHead,*slow=pListHead;
while(k)
{//考虑k大于结点数的情况,此时链表很早就为空了if(fast==NULL)return NULL;fast=fast->next;k--;
}
//同时走,直到fast为NULL,此时slow指向倒数第k个结点
while(fast)
{fast=fast->next;slow=slow->next;
}
//如果k<=0.那么第一个while循环不会进入,
//fast和slow同时走,最后都会指向空,所以不需要额外判断
return slow;
}

思路3:直接反转链表,然后直接找第k个结点

该方法直接改变了链表结构,使得phead变成了一个尾结点,与其他结点建立不起联系,所以该思路不行(尽量不要去改变原先链表的结构)在力扣中过不了。

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ){
//直接反转链表,然后找第k个结点
if(pListHead==NULL)
return NULL;
struct ListNode*p1=NULL;
struct ListNode*p2=pListHead;
struct ListNode*p3=pListHead->next;
int count=0;//用来数数
while(p2)
{p2->next=p1;p1=p2;p2=p3;if(p3)p3=p3->next;++count;
}
//此时的p1就是新链表的头结点
if(k<=count||k>count)
return NULL;
while(--k)
{
p1=p1->next;
}
return p1;
}

四、相交链表(力扣)

经典算法OJ题:相交链表

思路1:A链表逐个结点与B链表比较,如果存在相等,则就是相交结点(注:要比较指针而不能比较值,因为值是可以重复的)

空间复杂度:o(N^2)

时间复杂度:o(1)

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{ListNode* pcurA=headA;ListNode* pcurB=headB;while(pcurA){while(pcurB){if(pcurA==pcurB)return pcurA;pcurB=pcurB->next;}pcurB=headB;pcurA=pcurA->next;}return NULL;
}

思路2:长的链表往后走长度差,再同时走,直到相等就是相交点

空间复杂度:o(N)

时间复杂度:o(1)

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{ListNode * Apcur=headA;//用来遍历A链表ListNode * Bpcur=headB;//用来遍历A链表int a=0;//数a长度int b=0;//数b长度
while(Apcur)
{
Apcur=Apcur->next;
a++;
}
while(Bpcur)
{
Bpcur=Bpcur->next;
b++;
}
//找最小数,写俩while循环,只要大的数才可以走,小的走不了
int m=a>b?b:a;
while(a-m)
{headA=headA->next;a--;
}
while(b-m)
{headB=headB->next;b--;
}
while(headA)
{if(headA==headB)return headA;headA=headA->next;headB=headB->next;
}
return NULL;
}

五、链表的回文结构(牛客)

经典算法OJ题:链表的回文结构

思路1:找到中间结点,然后逆置后半段,然后将后续半段和前半段的链表同时走,如果其中一个走到空了值依旧是相等的,那么就是回文结构!!

空间复杂度:o(N)

时间复杂度:o(1)

ListNode *middleNode(struct ListNode *phead)
{
struct ListNode *fast,*slow;
fast=slow=phead;
while(fast!=NULL&&fast->next!=NULL)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
struct ListNode* reverseList(struct ListNode* head)
{//链表为空的时候if(head==NULL)return head;//链表不为空的时候,创建3个指针,分别指向前驱、当前、后继结点
struct ListNode*p1,*p2,*p3;
p1=NULL;//前驱
p2=head;//当前
p3=head->next;//后继
while(p2)
{//改变指向
p2->next=p1;
//向后挪动
p1=p2;
p2=p3;
//考虑p3为NULL的时候
if(p3)
p3=p3->next;
}
return p1;
}
class PalindromeList {
public:bool chkPalindrome(ListNode* A) {struct ListNode *mid=middleNode(A);//找中间结点struct ListNode *rmid=reverseList(mid);//逆序后半段while(rmid){if(A->val!=rmid->val)return false;A=A->next;rmid=rmid->next;}return true;}
};

六、随机链表的复制(力扣)

经典算法OJ题:随机链表的复制

思路1:1、插入拷贝结点到原结点的后面,2、控制拷贝结点的random,3、拷贝结点解下来,尾插到新链表上,同时恢复原链表

空间复杂度:o(N)

时间复杂度:o(N)

typedef struct Node Node;
Node* copyRandomList(Node* head) 
{if(head==NULL)return NULL;//将拷贝结点放在原结点的后面Node*pcur=head;while(pcur){Node*copy=(Node*)malloc(sizeof(Node));//拷贝结点copy->val=pcur->val;//插入copy->next=pcur->next;pcur->next=copy;//迭代pcur=pcur->next->next;}//控制拷贝结点的random指针pcur=head;while(pcur){//有可能random指向NULLNode* copy=pcur->next;if(pcur->random==NULL)copy->random=NULL;else//拷贝结点的random恰好在原结点的random后面copy->random=pcur->random->next;//迭代pcur=pcur->next->next;}//将拷贝结点解下来尾插到新链表上pcur=head;Node*newhead,*newtail,*temp;newhead=newtail=(struct Node*)malloc(sizeof(struct Node));temp=NULL;//用来记录遍历点while(pcur){Node* copy=pcur->next;temp=copy->next;//记录遍历点newtail->next=copy;//尾插newtail=newtail->next;//修复原链表pcur->next=temp;//继续遍历pcur=pcur->next;}Node*ret=newhead->next;//销毁哨兵结点前记住头结点free(newhead);newhead=NULL;return ret;
}

思路2:暴力拷贝链表,然后看原结点的random是原链表的第几个结点,对应的就是拷贝链表的的第几个结点

空间复杂度:o(N^2)

时间复杂度:o(N)

typedef struct Node Node;
Node* copyRandomList(Node* head) 
{if(head==NULL)return NULL;Node*pcur=head;Node*newhead,*newtail;newhead=newtail=(Node*)malloc(sizeof(Node));//哨兵结点while(pcur){Node*newnode=(Node*)malloc(sizeof(Node));newnode->val=pcur->val;newtail->next=newnode;newtail=newnode;//迭代pcur=pcur->next;}newtail->next=NULL;//要记住最后有个NULL;pcur=head;//回到链表头Node*newpcur=newhead->next;//用来遍历新链表头while(pcur){int s=0;//记录节点与head的距离Node*flag=head,*temp=pcur->random;//temp记住random结点while(flag!=temp){++s;flag=flag->next;}flag=newhead->next;//回到新链表的头while(s--)flag=flag->next;//找到了,就接上newpcur->random=flag;pcur=pcur->next;newpcur=newpcur->next;}Node*ret=newhead->next;free(newhead);newhead=NULL;return ret;
}

七、带环链表的快慢指针追击问题(力扣)

7.1 判断链表中是否有环

经典算法OJ题:判断链表是否带环

思路:快慢指针追击

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

7.2 返回链表开始入环的第一个结点

思路1:利用相遇点到入口点距离等于链表头到入口点距离的结论

 typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head)
{ListNode*fast,*slow;fast=slow=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;//相等,说明相遇了,链表带环if(slow==fast){ListNode*meet=slow;while(meet!=head){meet=meet->next;head=head->next;}return meet;}}  return NULL;
}

思路2:在相遇点将带环链表拆开,转化成求链表相交结点的问题

typedef struct ListNode ListNode;struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{ListNode * Apcur=headA;//用来遍历A链表ListNode * Bpcur=headB;//用来遍历A链表int a=0;//数a长度int b=0;//数b长度
while(Apcur)
{
Apcur=Apcur->next;
a++;
}
while(Bpcur)
{
Bpcur=Bpcur->next;
b++;
}
//找最小数,写俩while循环,只要大的数才可以走,小的走不了
int m=a>b?b:a;
while(a-m)
{headA=headA->next;a--;
}
while(b-m)
{headB=headB->next;b--;
}
while(headA)
{if(headA==headB)return headA;headA=headA->next;headB=headB->next;
}
return NULL;
}
struct ListNode *detectCycle(struct ListNode *head)
{ListNode*fast,*slow;fast=slow=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){//将带环链表的环拆开ListNode*newhead=slow->next;slow->next=NULL;return getIntersectionNode(newhead,head);}}return NULL;
}

7.3 追击问题扩展

根据前两题可以知道对于带环的链表,fast走2步,slow走1步

1、必然会相遇,不会错过

2、L=(n-1)*C+(C-x)   一个指针从相遇点走,一个指针从链表头走,最后会在入口点相遇

如果fast走3步,slow走1步,可以得到什么结论??

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

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

相关文章

Verilog刷题笔记21

题目&#xff1a; A priority encoder is a combinational circuit that, when given an input bit vector, outputs the position of the first 1 bit in the vector. For example, a 8-bit priority encoder given the input 8’b10010000 would output 3’d4, because bit[4…

幻方(Magic Square)

幻方&#xff08;Magic Square&#xff09; 幻方概述 什么是幻方呢&#xff1f;幻方&#xff08;Magic Square&#xff09;就是指在nn&#xff08;n行n列&#xff09;的方格里填上一些连续的数字&#xff0c;使任意一行、任意一列和对角线上的数字的和都相等。例如有33的3行3…

【PyQt】06-.ui文件转.py文件

文章目录 前言方法一、基本脚本查看自己的uic安装目录 方法二、添加到扩展工具里面&#xff08;失败了&#xff09;方法二的成功步骤总结 前言 方法一、基本脚本 将Qt Designer&#xff08;一种图形用户界面设计工具&#xff09;生成的.ui文件转换为Python代码的脚本。 pytho…

【大模型上下文长度扩展】LongLoRA:长序列大模型微调新方式

LongLoRA&#xff1a;长序列大模型微调新方式 核心问题子问题1: 上下文窗口限制子问题2: 计算资源限制子问题3: 高效微调方法的缺乏低秩权重更新&#xff08;LoRA&#xff09;S2-Attn&#xff08;Shifted Sparse Attention&#xff09; 分析不足 扩展大模型处理长上下文能力不同…

Netty核心原理与基础实战(二)——详解Bootstrap

接上篇&#xff1a;Netty核心原理与基础实战&#xff08;一&#xff09; 1 Bootstrap基础概念 Bootstrap类是Netty提供的一个便利的工厂类&#xff0c;可以通过它来完成Netty的客户端或服务端的Netty组件的组装&#xff0c;以及Netty程序的初始化和启动执行。Netty的官方解释是…

【数据结构与算法】二叉树(Binary Tree)

相关推荐&#xff1a;堆&#xff08;Heap&#xff09; / 堆排序&#xff08;HeapSort&#xff09; / TopK 文章目录 1.树1.1 树相关概念1.2 举例树的应用 2. 二叉树2.1 二叉树分类2.2 特殊的二叉树2.3 二叉树的存储结构 3. 二叉树实现与热门问题 1.树 树是一种非线性的数据结构…

力扣:42. 接雨水 84.柱状图中最大的矩形(单调栈,双指针)

这两道题解题思路类似&#xff0c;一个是单调递增栈&#xff0c;一个是单调递减栈。本篇博客给出暴力&#xff0c;双指针和单调栈解法。 42. 接雨水 题目&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后…

AMD64 linux 环境中,如何将main.go打包成不带 .exe 的可执行文件?

在终端中先进入main.go所在的文件夹&#xff0c;然后运行这三条命令即可 $env:GOOS"linux" $env:GOARCH"amd64" go build main.go 最终结果&#xff0c;成功出现不带 .exe 结尾的可执行包&#xff1a;

日本失去的三十年:去杠杆用了14年

去年以来&#xff0c;日股在日本央行转鹰预期、基本面改善和一系列监管新规的催化下高歌猛进&#xff0c;日经指数已经逼近90年代资产泡沫时期的高位。今年迄今累计上涨8.51%&#xff0c;领跑全球&#xff0c;“失落的三十年”似乎已经远去。 日本因何走向衰退&#xff1f;“失…

【C语言】位与移位操作符详解

目录 1.⼆进制和进制转换 ①十进制&#xff1a;生活中最常用 ②二进制&#xff1a;计算机中使用的&#xff0c;每个数字称为一个比特 ③八进制、十六进制也如上 ④二进制转十进制 ⑤十进制转二进制 ⑥二进制转八进制 ⑦二进制转十六进制 2.原码、反码、补码 3.移位操…

【已更新】2024美赛C题代码教学思路数据处理数学建模分析Momentum in Tennis

问题一完整的代码已给出&#xff0c;预计2号晚上或者3号凌晨全部给出。 代码逻辑如下&#xff1a; C题第一问要求我们开发一个模型&#xff0c;捕捉得分时的比赛流程&#xff0c;并将其应用于一场或多场比赛。你的模型应该确定哪名球员在比赛的特定时间表现得更好&#xff0c;…

AI-数学-高中-24-三角函数一般形式的各参数含义

原作者视频&#xff1a;三角函数】12三角函数一般形式的各参数含义&#xff08;易&#xff09;_哔哩哔哩_bilibili 1.函数中的A标识符&#xff1a;表示曲线中间平衡位置的振幅&#xff0c;值域为正负A&#xff1a;[-A,A]。 2.函数中的B标识符&#xff1a;决定曲线纵向上下平移…

基于 SpringBoot 和 Vue.js 的权限管理系统部署教程

大家后&#xff0c;我是 jonssonyan 在上一篇文章我介绍了我的新项目——基于 SpringBoot 和 Vue.js 的权限管理系统&#xff0c;本文主要介绍该系统的部署 部署教程 这里使用 Docker 进行部署&#xff0c;Docker 基于容器技术&#xff0c;它可以占用更少的资源&#xff0c;…

linux文件的IO函数

open函数: 作用&#xff1a;打开或者新建一个文件 原型&#xff1a; int open(const char*pathname,int flags); int open(const char*pathname,int flags,mode_t mode); 参数&#xff1a; pathname:路径 flags:1-> O_RONLY 只读打开 2 -> O_WONLY只写打开 3->…

83 CTF夺旗-Python考点SSTI反序列化字符串

这里写目录标题 CTF各大题型简介演示案例:CTF夺旗-Python-支付逻辑&JWT&反序列化CTF夺旗-Python-Flask&jinja2&SSTl模版注入CTF夺旗-Python-格式化字符串漏洞&读取对象 涉及资源&#xff1a; 我们这篇文章主要讲的是CTF在web渗透测试方向的3个考点 CTF各大…

elementui常用组件-个人版(间断更新)

Dialog 对话框 el-dialog <el-dialogtitle"提示":visible.sync"dialogVisible"width"30%":before-close"handleClose"><span>这是一段信息</span><span slot"footer" class"dialog-footer"…

微信小程序(三十六)事件传参

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.传参步骤 2.传参接收解构步骤 源码&#xff1a; index.wxml <button type"primary" bind:tap"onclick" mark:index"{{0}}" mark:remb"{{1}}" class"But&quo…

产品经理--分享在项目中产品与研发之间会遇到的问题 在面试这一岗位时,面试官常问的问题之一,且分享两大原则来回答面试官这一问题

目录 一.STAR原则 1.1 简介 1.2 如何使用 1.3 举例说明 二.PDCA原则 2.1 简介 2.2 如何使用 2.3 运用场景 2.4 举例说明 三.产品与研发的沟通痛点 3.1 沟通痛点的原因 3.2 分享案例 前言 本篇会详细阐明作为一个产品经理会在项目遇到的问题&#xff0c;如&#xff1a;产…

张艺谋《主角》选角引发热议,周迅、赵丽颖、杨紫或成候选。

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 近日&#xff0c;张艺谋执导的首部电视剧《主角》女主选角成为…

6.electron之上下文隔离,预加载JS脚本

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中&#xff0c;因此它允许你仅需一个代码仓库&#xff0c;就可以撰写支持 Windows、…