C语言每日一练(二)

单链表经典算法专题

一、 单链表相关经典算法OJ题1移除链表元素

解法一:在原链表中删除Node.next=next的节点
typedef  struct ListNode ListNode;
struct ListNode* removeElements( ListNode* head, int val) {
	ListNode* pcur = head;
	ListNode* pre = head;

	while (pcur)
	{
		while (pcur->val != val )
		{
			pre = pcur;
			pcur = pcur->next;
			if (pcur == NULL)
			{
				return head;
			}
		}
		if (head->val == val)
		{
			head = head->next;
			pcur = head;
			pre = head;
		}
		else if (pcur->val == val)
		{
			pcur = pcur->next;
			pre->next = pcur;
		}
	}

	return head;
}
注意:当头节点的val==val时,要改变头节点的位置
解法二:创建新的指向头尾的链表
typedef  struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val){
     ListNode * newHead=NULL;
     ListNode * newTail=NULL;
     ListNode* pcur=head;
     while(pcur)
     {
         if(pcur->val!=val)
         {
             if(newHead==NULL)
             {
                 newHead=pcur;//注意这里不能写head
                 newTail=pcur;
             }
             else 
             {
                 newTail->next=pcur;
                 newTail=newTail->next;
             }
            
         }
        
         
         pcur=pcur->next;
     }
     if(newTail)
     {
         newTail->next=NULL;
     }
     return newHead;

}
注意:这里如果写head的话,当一个节点是要删除的节点,头节点还是那个删除的节点。

二、单链表相关经典算法OJ题2:反转链表

解法一:创建新链表,对新链表进行头插
typedef struct ListNode SLNode;
struct ListNode* reverseList(struct ListNode* head){
   SLNode* newHead = NULL;
	SLNode* newTail = NULL;
	SLNode* pcur = head;
	SLNode* last = head;


	while (head!=NULL)
	{
	
		if (newHead == NULL)
		{
			newHead = newTail = head;
			
			
			head = head->next;
		}
		else
		{
			last = head;
			
			
			head = head->next;
			pcur = last;
			pcur->next = newHead;
			newHead = pcur;
		}
		
	}
  if (newTail!=NULL)
  {
      	newTail->next = NULL;
  }
	return newHead;




}
    

解法二:定义三个变量,n1,n2,n3(n1,n2用来反转指向,n3在前面遍历)

typedef  struct ListNode ListNode;
struct ListNode* reverseList( ListNode* head) {
	if(head==NULL)
    {
        return NULL;
    }
        ListNode * n1=NULL;
	ListNode * n2=head;
	ListNode * n3=head->next;
   
    while(n2)
    {
         n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
      {
            n3=n3->next;
      }
       
    }
   
    return n1;
}

三、 单链表相关经典算法OJ题3合并两个有序链表

解法一:在原链表基础上进行修改,会使用到指定位置之前插入数
 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
if (list1 == NULL)
	{
		return list2;
	}
	if (list2 == NULL)
	{
		return list1;
	}
	ListNode* pcur1 = list1;
	ListNode* pre =list1;

	ListNode* pcur2 = list2;
	ListNode* pcur3 = list2->next;
	while (pcur1 && pcur2)
	{
		while (pcur1->val < pcur2->val)
		{
			pre = pcur1;
			pcur1 = pcur1->next;
			if (pcur1 == NULL)
			{
				pre->next = pcur2;
				return list1;
			}
		}
		if (list1->val > pcur2->val)
		{
			pcur2->next = list1;
			list1 = pcur2;
			pre = list1;
			pcur2 = pcur3;
			if (pcur3 != NULL)
			{
				pcur3 = pcur3->next;
			}
		}
		//在pur1实现头插
		else
		{
			pre->next = pcur2;
			pcur2->next = pcur1;
			pcur2 = pcur3;
			if (pcur3 != NULL)
			{
				pcur3 = pcur3->next;
			}
		}

	}
	return list1;
}

 输出结果:

解法二:创建一个新的空链表,遍历俩个链表,进行新链表的尾插

(使用单链表)无头单向不循环链表

 typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
if (list1 == NULL)
	{
		return list2;
	}
	if (list2 == NULL)
	{
		return list1;
	}
  ListNode* newhead=NULL;
	ListNode* newtail=NULL;
	ListNode* pcur1=list1;
	ListNode* pcur2=list2;
	while(pcur1&&pcur2)
	{
		if(pcur1->val<pcur2->val)
		{
			if(newhead==NULL)//插入新链表
			{
				newhead=newtail=pcur1;
			}
			else
			{
        newtail->next=pcur1;
				newtail=newtail->next;
			}
				pcur1=pcur1->next;
		}
	
		else
		{
       	if(newhead==NULL)//插入新链表
			{
				newhead=newtail=pcur2;
			}
			else
			{
        newtail->next=pcur2;
				newtail=newtail->next;
			}
				pcur2=pcur2->next;
		}
	

	}
	if(pcur1==NULL)
	{
		newtail->next=pcur2;
	}
	if(pcur2==NULL)
	{
		newtail->next=pcur1;
	}
	return newhead;
}

优化解法二(使用带头单向不循环链表)

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
if (list1 == NULL)
	{
		return list2;
	}
	if (list2 == NULL)
	{
		return list1;
	}
	 ListNode* newhead,*newtail;
  newhead= newtail=(ListNode*)malloc(sizeof(ListNode));

	ListNode* pcur1=list1;
	ListNode* pcur2=list2;
	while(pcur1&&pcur2)
	{
		if(pcur1->val<pcur2->val)
		{
			//直接插入新链表
		
		
        newtail->next=pcur1;
				newtail=newtail->next;
		
				pcur1=pcur1->next;
		}
	
		else
		{
       
        newtail->next=pcur2;
				newtail=newtail->next;
			
				pcur2=pcur2->next;
		}
	

	}
	if(pcur1==NULL)
	{
		newtail->next=pcur2;
	}
	if(pcur2==NULL)
	{
		newtail->next=pcur1;
	}
	ListNode * rethead=newhead->next;
	free(newhead);
	newhead=NULL;
	return rethead;;
}

 注:相比较与不带头链表,带头链表省略了反复判断头节点是否为空,直接插入头的后面,所带的头不带任何数据,所以返回的时候,返回头的next.

四、单链表相关经典算法OJ题4链表的中间结点

解法一:使用快慢指针

//快慢指针
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head){
    if(head==NULL)
    {
        return NULL;
    }
    ListNode * slow,*fast;
    slow=head;
    fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    return slow;

}

注:这种快慢指针可以运用到寻找单链表的倒数第几个节点,比如说,找倒数第3个节点,只需要让慢指针与快指针相差3个节点,当快指针走到NULL,此时慢指针为倒数第3个节点。

还有一点值得注意的是 while(fast&&fast->next)该位置判断不能颠倒,因为可能fast为空,此时先判断fast->next会报错。

五、 循环链表经典应⽤-环形链表的约瑟夫问题

著名的Josephus问题
据说著名犹太 历史学家 Josephus有过以下的故事:在罗⻢⼈占领乔塔帕特后,39 个犹太⼈与
Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被⼈抓到,于是决定了⼀个⾃杀 ⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀ 个重新报数,直到所有⼈都⾃杀⾝亡为⽌。 然⽽Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在第16个与第31个位置,于是逃过了这场死亡游戏。

解法一:创建一个单向循环链表,遇到计数等于m的节点删除,剩下最后一个节点的val值即为所求编号

typedef   struct ListNode   ListNode;
ListNode * SLbuyNode(int x)//创造一个节点
{
    ListNode * Node=(ListNode*)malloc(sizeof(ListNode));
    Node->val=x;
    Node->next= NULL;
    return Node;
}
//创建一个循环链表
ListNode *CreatSLNode(int n)
{
    ListNode * head=SLbuyNode(1);
    ListNode * tail=head;
    for(int i=2;i<=n;i++)
    {
        tail->next=SLbuyNode(i);
        tail=tail->next;
    }
      tail->next=head;
      return tail;
}

int ysf(int n, int m ) {
   
   ListNode*  prev=CreatSLNode(n);
   ListNode*  pcur=prev->next;
   int count=1;
   while(pcur->next!=pcur)
   {
      
      if(count==m)//报到m的节点删除
      {
        prev->next=pcur->next;
        free(pcur);
        pcur=prev->next;
        count=1;
      }
      else //没报m继续往前走
      {
         prev=pcur;
         pcur=pcur->next;
         count++;
      }
      
   }
   return pcur->val;
}

注意:红框若改成SLbuyNode(1),表示tail又重新开辟一块空间,和head不是同一片空间,所以连不起来。

 

六、 单链表相关经典算法OJ题5分割链表 

解法一:创建俩个带头单向不循环链表,将大于等于x和小于x的节点,分别放入俩个空链表,然后小链表和大链表头尾相接

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
    if(head==NULL)
    {
        return NULL;
    }

    ListNode * maxhead,*maxtail;
    ListNode * minhead,*mintail;
    maxhead= maxtail=(ListNode*)malloc(sizeof(ListNode));
  
    minhead=mintail=(ListNode*)malloc(sizeof(ListNode));
    ListNode *pcur=head;
    while(pcur)
    {
        if(pcur->val<x)
        {
            mintail->next=pcur;
            mintail=mintail->next;
            pcur=pcur->next;
        }
        else
        {
            maxtail->next=pcur;
            maxtail=maxtail->next;

            pcur=pcur->next;
        }
    }
    if(maxtail->next!=NULL)
    {
            maxtail->next=NULL;
    }
    mintail->next=maxhead->next;
   ListNode*ret= minhead->next;
   free(maxhead);
   maxhead=NULL;
   free(minhead);
   minhead=NULL;
    return ret;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CVE-2021-44228 Apache log4j 远程命令执行漏洞

一、漏洞原理 log4j(log for java)是由Java编写的可靠、灵活的日志框架&#xff0c;是Apache旗下的一个开源项目&#xff0c;使用Log4j&#xff0c;我们更加方便的记录了日志信息&#xff0c;它不但能控制日志输出的目的地&#xff0c;也能控制日志输出的内容格式&#xff1b;…

【数据结构】插入排序

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 直接插入、希尔排序 1. 什么是排序2…

lesson2(补充)关于>>运算符和<<运算符重载

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言&#xff1a; cout和cin我们在使用时需要包含iostream头文件&#xff0c;我们可以知道的是cout是写在ostream类里的&#xff0c;cin是写在istream类里的&#xff0c;他们都是定义出的对象&#xff0c;而<< 和 >…

c++多线程

目录 一、进程与线程 二、多线程的实现 2.1 C中创建多线程的方法 2.2 join() 、 detach() 和 joinable() 2.2.1 join() 2.2.2 detach() 2.2.3 joinable() 2.3 this_thread 三、同步机制&#xff08;同步原语&#xff09; 3.1 同步与互斥 3.2 互斥锁&#xff08;mu…

笔记本电脑搜索不到wifi6 无线路由器信号

路由器更换成wifi6 无线路由器后&#xff0c;手机能搜索到这个无线信号&#xff0c;但是笔记本搜索不到这个无线信号&#xff0c;后网上搜索后发现是无线网卡驱动问题&#xff0c;很多无线网卡使用的是Intel芯片&#xff0c;Intel就此发布了公告&#xff0c;升级驱动就可以彻底…

npm install报错,解决记录

第一步&#xff1a;检查和安装 我这里建议检查 1.node.js版本是否和前使用版本一致 2.npm版本是否和前使用版本一致 3.vue版本是否和前使用版本一致 4.vue脚手架是否和前使用版本一致 5.npm镜像是否和前使用版本一致 1.检查版本 【node版本】 命令&#xff1a;node -v 结果&a…

【C++初阶】类和对象——操作符重载const成员函数取地址重载日期类的实现

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C头疼记 目录 前言&#xff1a; 运算符重载 运算符重载 赋值运算符重载 前置和后置重载 const成员 取地址及const取地址操作符重载 使用函数操作符重载完成日期类的实现 前言&#xff1a; 上篇文…

校园物业报修小程序开发笔记一

背景 校园规模和复杂性&#xff1a; 大型学校和校园通常拥有众多的建筑物、设施和设备&#xff0c;需要有效的维护和报修系统&#xff0c;以满足学生、教职员工和校园管理人员的需求。 学生和员工需求&#xff1a; 学生和员工在校园内可能遇到各种维修问题&#xff0c;如故障的…

公网IP怎么设置?公网ip有哪些优点和缺点?

随着互联网的普及&#xff0c;越来越多的人开始关注网络安全和隐私保护。其中&#xff0c;公网IP的设置成为了一个备受关注的话题。本文将详细介绍公网IP的设置方法以及公网IP的优点和缺点。 一、公网IP设置方法 1. 路由器设置 在家庭或企业网络中&#xff0c;路由器通常是最重…

[C++进阶篇]STL以及string的使用

目录 1. 什么是STL 2. STL库的六大组件 3. 标准库中的string类 3.3 对比size和capacity接口函数 size代表字符串有效长度 capacity代表字符串的实际长度 3.4 reserve&#xff0c;resize函数的使用 3.5 string类的访问和遍历 4. string的修改操作 5. insert和e…

电厂数据可视化三维大屏展示平台加强企业安全防范

园区可视化大屏是一种新型的信息化手段&#xff0c;能够将园区内各项数据信息以图像的形式直观呈现在大屏幕上&#xff0c;便于管理员和员工进行实时监控、分析和决策。本文将从以下几个方面介绍园区可视化大屏的作用和应用。 VR数字孪生园区系统是通过将实际园区的各种数据和信…

【计算机视觉】相机

文章目录 一、原始的相机&#xff1a;针孔相机&#xff08;Pinhole Camera&#xff09;二、针孔相机的数学模型三、真实相机四、透镜的缺陷 我的《计算机视觉》系列参考UC Berkeley的CS180课程&#xff0c;PPT可以在课程主页看到。 成像原理 一、原始的相机&#xff1a;针孔相机…

Linux redis 安装

1、解压 tar -zxvf redis-5.0.10.tar.gz 2、cd /data/redis-5.0.10 文件夹 3、make 等待make命令执行完成即可。 make命令报错&#xff1a;cc 未找到命令&#xff0c;系统中缺少gcc&#xff0c;执行命令安装 gcc&#xff1a; yum -y install gcc automake autocon…

【2023Mathorcup大数据】B题 电商零售商家需求预测及库存优化问题 python代码解析

【2023Mathorcup大数据】B题 电商零售商家需求预测及库存优化问题 python代码解析 1 题目 2023 年MathorCup 高校数学建模挑战赛——大数据竞赛赛道B&#xff1a;电商零售商家需求预测及库存优化问题电商平台存在着上千个商家&#xff0c;他们会将商品货物放在电商配套的仓库…

【刷题宝典NO.1】

Nim游戏 https://leetcode.cn/problems/nim-game/description/ 你和你的朋友&#xff0c;两个人一起玩 Nim 游戏&#xff1a; 桌子上有一堆石头。 你们轮流进行自己的回合&#xff0c; 你作为先手 。 每一回合&#xff0c;轮到的人拿掉 1 - 3 块石头。 拿掉最后一块石头的人…

TextureView和SurfaceView

1、Surface Surface对应了一块屏幕的缓冲区&#xff0c;每一个window对应一个Surface&#xff0c;任何View都是画在Surface上的&#xff0c;传统的View共享一块屏幕缓冲区&#xff0c;所有的绘制都必须在UI线程上进行。 2、SurfaceView 顾名思义就是Surface的View&#xff0c;…

AWTK 液体流动效果控件发布

液体流动效果控件。 主要特色&#xff1a; 支持水平和垂直方向。支持正向和反向流动。支持设置头尾的图片。支持设置流动的图片。支持设置速度的快慢。支持启停操作。 准备 获取 awtk 并编译 git clone https://github.com/zlgopen/awtk.git cd awtk; scons; cd -运行 生成…

Ansible脚本进阶---playbook

目录 一、playbooks的组成 二、案例 2.1 在webservers主机组中执行一系列任务&#xff0c;包括禁用SELinux、停止防火墙服务、安装httpd软件包、复制配置文件和启动httpd服务。 2.2 在名为dbservers的主机组中创建一个用户组&#xff08;mysql&#xff09;和一个用户&#xf…

java项目之机房预约系统(ssm框架)

项目简介 机房预约系统实现了以下功能&#xff1a; 管理员&#xff1a;个人中心、学生管理、教师管理、机房号管理、机房信息管理、申请预约管理、取消预约管理、留言板管理、论坛管理、系统管理。学生&#xff1a;个人中心、机房信息管理、申请预约管理、取消预约管理、留言…

大数据可视化BI分析工具Apache Superset实现公网远程访问

大数据可视化BI分析工具Apache Superset实现公网远程访问 文章目录 大数据可视化BI分析工具Apache Superset实现公网远程访问前言1. 使用Docker部署Apache Superset1.1 第一步安装docker 、docker compose1.2 克隆superset代码到本地并使用docker compose启动 2. 安装cpolar内网…