单链表OJ思路

目录

前言

一、移除链表元素

二、反转链表

三、链表的中间结点

四、返回倒数第k个结点

五、合并两个有序链表

六、链表分割

七、链表的回文结构

八、相交链表

九、环形链表

十、环形链表||

十一、随机链表的赋值


前言

        11道单链表OJ题的解题思路。


一、移除链表元素

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

思路:

  1. 创建两个指针 newHead, newTail 指向新链表的头尾,这个新链表还是由原链表组成,只不过是去除了指定要删除的结点。
  2. 再定义一个指针 pcur 去遍历原链表,与要删除的数据值 val 比较,只要不是要删除的结点,就尾插到新链表的尾部。
  3. 细节:第一次尾插时需要注意,此时 newHead 和 newTail 都为空,需要将第一个结点分别赋值给 newHead 和 newTail。第二次及以上时就只需要尾插即可,插到 newTail 的 next 指针,插入后,newTail 需走到新结点位置为下一次插入做准备。
  4. 还有一个需要情况需要注意:
  5. 如图原链表中的最后一个结点是需要被删除的,可是在上述思路得到的新链表中,结点 5 的 next 指针指向的依旧是需要删除的结点 6,因此我们最后需要判断一下,如果尾结点 newTail 不为空,就将其 next 指针设置为 NULL。

代码:

typedef struct ListNode SLTNode;struct ListNode* removeElements(struct ListNode* head, int val) 
{SLTNode*newHead,*newTail;newHead=newTail=NULL;SLTNode*pcur = head;//pcur遍历while(pcur){//值不为val进行尾插if(pcur->val!=val){//第一次尾插if(newHead==NULL){newHead=newTail=pcur;}else{newTail->next=pcur;newTail=newTail->next;}}pcur=pcur->next;}//只要不是空链表就将尾结点的next指针置空if(newTail)newTail->next=NULL;return newHead;
}


二、反转链表

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

思路:

  1. 反转单链表使用的是三指针法,即 pcur(指向头结点),prev(指向pcur的上一个结点),next(指向pcur的下一个结点)。
  2. 注意 prev 第一次是指向 NULL。
  3. 反转方法:pcur 用于遍历单链表并反转链表,next 提前储存 pcur 的下一个结点方便 pcur 遍历,prev 储存 pcur 的上一个结点方便 pcur 反转时找到上一个结点。操作顺序:首先初始化三指针,然后 pcur 修改当前结点的 next 指针指向 prev,再 prev 走到 pcur 位置,再将 pcur 移动到 next 位置,最后让 next 指针走到 pcur 的下一个结点。重复上述步骤直到 pcur 为空。
  4. 最后 prev 刚好指向反转后的链表头结点,返回 prev 即可

代码:

typedef struct ListNode SLTNode;struct ListNode* reverseList(struct ListNode* head) 
{//三指针法SLTNode*prev = NULL;SLTNode*pcur = head;while(pcur){SLTNode*next = pcur->next;pcur->next=prev;prev=pcur;pcur=next;}return prev;
}


三、链表的中间结点

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

思路:

  1. 快慢指针法。定义一个 fast 指针每次移动两个结点,定义一个 slow 指针每次移动一个结点。
  2. 当 fast 指针走完链表后,slow 指针指向的就是中间节点。
  3. 可以想象有两人在同一起点围绕操场跑一圈,甲的速度为乙的两倍,甲跑完了,乙只跑了一半。
  4. 唯一需要注意的细节就是循环结束的条件为 while(pcur && pcur->next),即以下两种情况
  5. fast 有两种情况会导致循环结束,一种即为 next 指针为空,此时不能连跳两个结点因为不能对空指针解引用。一种为 fast 已经为空。

代码:

typedef struct ListNode SLTNode;struct ListNode* middleNode(struct ListNode* head) 
{//快慢指针法SLTNode*prev=head;SLTNode*pcur=head;while(pcur && pcur->next){pcur=pcur->next->next;prev=prev->next;}return prev;
}


四、返回倒数第k个结点

链接:面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)

思路:

  1. 这题思路与快慢指针类似,既然要求倒数第k个结点,那我们先定义一个指针走k个结点,再定义一个指针指向链表头结点,然后让这两个指针一次走一个结点直到先走了k个结点的指针走到了空指针。那么另外一个指针的位置就是倒数第k个结点了。
  2. 定义一个指针 pcur 走k个结点,再定义一个指针 prev 指向头结点。然后两指针都每次移动一个结点。
  3. 最后结果:
  4. 原理:可以想象两个人走路,同一起点,A先走了2步,那么B一开始就落后 A 2步,然后两人同时走路,保持一样的速度每秒一步,那么A走到了终点,B还差2步。

代码:

typedef struct ListNode SLTNode;int kthToLast(struct ListNode* head, int k) 
{SLTNode*prev=head;SLTNode*pcur=head;//pcur先走k步while(k--){pcur=pcur->next;}//同步走while(pcur){pcur=pcur->next;prev=prev->next;}return prev->val;
}


五、合并两个有序链表

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

思路:

  1. 这题我个人是采取了类似归并排序的思路。代码写的有点冗余。
  2. 简单点说定义三个指针 prev,pcur,newTail,prev用于遍历链表list1,pcur用于遍历链表list2,newTail为新链表的尾指针。然后第一个循环分别比较 prev,pcur对应结点的值,然后将小的插入到 newTail 处。该循环结束后还需要两个循环分别判断 list1,list2是否有剩余数据,有就将其尾插到 newTail 处,最后比较 list1, list2 第一个节点的大小,返回小的哪个头结点。
  3. 需要注意的是开头需要判断两个链表是否有空链表,如果有一个为空,直接返回另一个链表头结点即可。

代码:

typedef struct ListNode SLTNode;struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{if(list1==NULL){return list2;}if(list2==NULL){return list1;}SLTNode* prev = list1;SLTNode* pcur = list2;SLTNode* newTail = NULL;//遍历比较两个链表while (prev && pcur){if (prev->val < pcur->val){if (newTail == NULL){newTail = prev;}else{newTail->next = prev;newTail = newTail->next;}prev = prev->next;}else{if (newTail == NULL){newTail = pcur;}else{newTail->next = pcur;newTail = newTail->next;}pcur = pcur->next;}}//一定会有个链表数据没有插入到新链表中while (prev){newTail->next = prev;newTail = newTail->next;prev = prev->next;}while (pcur){newTail->next = pcur;newTail = newTail->next;pcur = pcur->next;}//通过比较两个链表第一个值返回小的头结点return  list1->val < list2->val ? list1 : list2;
}

优化:

typedef struct ListNode ListNode;struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{if(list1==NULL){return list2;}if(list2==NULL){return list1;}ListNode* l1 = list1;ListNode* l2 = list2;ListNode*newHead,*newTail;//让newHead newTail指向同一块空间方便后续返回newHead = newTail = (ListNode*)malloc(sizeof(ListNode));while(l1 && l2){if(l1->val < l2->val){newTail->next=l1;newTail=newTail->next;l1=l1->next;}else{newTail->next=l2;newTail=newTail->next;l2=l2->next;}}while(l1){newTail->next=l1;newTail=newTail->next;l1=l1->next;}while(l2){newTail->next=l2;newTail=newTail->next;l2=l2->next;}ListNode*ret = newHead->next;free(newHead);return ret;
}
  • 仅减少了一下分支结构,如果你有更简洁并且高效的代码欢迎评论区分享。


六、链表分割

链接:链表分割_牛客题霸_牛客网

思路:

  1. 创建两个新链表,将小于x的结点存在一个链表中,大于等于x的结点存在另一个链表中。最后将两个新链表连接。
  2. 依旧创建一个 pcur 指针遍历原链表
  3. 分别尾插后:
  4. 合并,最终结果:
  5. 细节:记得将最后一结点的next指针置空

代码:

class Partition 
{
public:ListNode* partition(ListNode* pHead, int x) {// write code hereListNode*newHead1 = (ListNode*)malloc(sizeof(ListNode));ListNode*newHead2 = (ListNode*)malloc(sizeof(ListNode));//头尾指针开始都指向同一开辟的空间,方便后续返回和freeListNode*newTail1 = newHead1;ListNode*newTail2 = newHead2;ListNode*pcur = pHead;//分别尾插while(pcur){if(pcur->val < x){newTail1->next=pcur;newTail1=newTail1->next;}else {newTail2->next=pcur;newTail2=newTail2->next;}pcur=pcur->next;}//尾结点置空newTail2->next=NULL;//连接newTail1->next=newHead2->next;ListNode*ret = newHead1->next;free(newHead1);free(newHead2);newHead1=newHead2=NULL;return ret;}
};


七、链表的回文结构

链接:链表的回文结构_牛客题霸_牛客网

思路:

  1. 局限解法:因为这题保证了链表长度小于900,那么我们可以创建一个900元素的数组保存链表的每一个结点的值,然后在数组中判断是否是回文结构,数组判断回文相对来说就简单很多,头尾往中间两两比较即可。缺点:如果相同一道题,不保证链表长度,并且空间复杂度为O(1),那么这个方法就不行。
  2. 通用解法:第一步---找到中间结点,第二步---逆置后半段链表,第三步---两两比较。
  3. 我们实现通用解法:
  4. 该方法结合了前面两题的解法:1.找中间结点,2.逆置链表
  5. 细节:反转右半段链表时,依旧使用三指针法,需要注意的是mid结点的next指针指向为NULL

代码:

class PalindromeList {
public://找中间结点ListNode* findMidNode(ListNode* A){ListNode*fast = A;ListNode*slow = A;while(fast && fast->next){fast=fast->next->next;slow=slow->next;}return slow;}//逆置链表ListNode* reverseList(ListNode* mid){ListNode*n1, *n2;n1=NULL, n2=mid;while(n2){ListNode*n3=n2->next;n2->next=n1;n1=n2;n2=n3;}return n1;}bool chkPalindrome(ListNode* A) {// write code here//1.找中间结点ListNode* mid = findMidNode(A);//2.将后半段链表逆置ListNode* right = reverseList(mid);//3.逐一对比ListNode*left = A;while(right){if(left->val != right->val){return false;}left=left->next;right=right->next;}return true;}
};


八、相交链表

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

思路:

  1. 首先分别遍历两个链表,计算它们的链表大小 sizeA和sizeB,然后根据大小创建两个指针 longList和shortList 分别指向长链表和短链表。
  2. 我们先让长链表走 |sizeA-sizeB| 步,这样就可以保证两链表剩余长度一致,就可以同时遍历两个链表并且判断相交点在何处。
  3. 这题主要难在理解上,两个链表相交,那么相交以后的链表长度肯定是一样长的,因为是单链表,只有一个next指针,不可能相交后再分叉。因此遍历两个链表前应该保证两个链表长度一致。

代码:

typedef struct ListNode ListNode;struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{int sizeA = 0;int sizeB = 0;ListNode*l1,*l2;l1 = headA;l2 = headB;//计算链表A的大小while(l1){++sizeA;l1=l1->next;}//计算链表B的大小while(l2){++sizeB;l2=l2->next;}//区分长短链表ListNode* longList = headA;ListNode* shortList = headB;if(sizeB>sizeA){longList = headB;shortList = headA;}int gap = abs(sizeA-sizeB);//让长的链表先走到与短链表一样长的位置while(gap--){longList=longList->next;}//同时遍历两个链表找出相交节点while(shortList && longList){if(shortList==longList){return shortList;}shortList=shortList->next;longList=longList->next;}return NULL;
}


九、环形链表

链接:141. 环形链表 - 力扣(LeetCode)

思路:

  1. 快慢指针法。
  2. 这题可以使用快慢指针快速解决,因为假如存在环形结构,两指针都进入环内,快指针 fast 的速度是慢指针 slow 的两倍,那么快指针一定会在环内追上慢指针。
  3. 只要他俩相遇,就说明有环。

代码:

typedef struct ListNode ListNode;bool hasCycle(struct ListNode *head) 
{//快慢指针法ListNode*fast=head;ListNode*slow=head;while(fast && fast->next){fast=fast->next->next;slow=slow->next;if(fast==slow){return true;}}return false;
}


十、环形链表||

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

思路:

  1. 这题是在上一题的基础上要返回入环的第一个节点。
  2. 这是一道经典的 Floyd's Cycle-Finding Algorithm(也称为“龟兔赛跑”算法)
  3. 方法:依旧快慢指针找到它们第一次相遇的节点,然后保持其中一个指针不动,将另外一个指针回归到链表的头节点处。然后改变它们的速度每次都只走一步,同时开始移动,直到它们再次相遇,第二次相遇的节点就是入环的第一个节点。
  4. 原理:

代码:

typedef struct ListNode ListNode;struct ListNode *detectCycle(struct ListNode *head) 
{ListNode*slow=head;ListNode*fast=head;//找相遇点,找到返回并重设slow位置while(fast && fast->next){slow=slow->next;fast=fast->next->next;if(fast==slow){slow=head;break;}}//找第二次相遇点while(fast && fast->next){if(fast==slow){return slow;}slow=slow->next;fast=fast->next;}return NULL;
}


十一、随机链表的赋值

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

思路:

  1. 这题讲的是“深拷贝”,即新链表的节点与原链表只是值和random指向关系一样,新链表的节点都是 malloc 开辟出来的。
  2. 第一步,我们需要得到与原链表值相同的节点,而且数量也需要一致,先不管 random 指针。方法:我们单独创建一个方法 AddNode 创建新的节点,另外还有一个方法 BuyNode 用来申请新节点。在 AddNode 方法中,我们创建一个 pcur 指针用来遍历原链表,遍历的同时申请新节点。为了实现边遍历边拷贝,将新节点连接到原链表上:
  3. 以上就是第一步,在原链表的基础上拷贝出新节点,此时新节点都连接在原链表上。
  4. 第二步,为新节点连接 random 指针,我们以上面新节点 13 为例,它的 random 指针因该指向 7 的,我们使用两个指针遍历,一个指针 pcur 遍历原节点,一个 copy 遍历新节点,同步遍历,也就是说 pcur 指向是什么,copy 指向的就是 pcur 节点的复制节点,那么对于 13 来说,代码 copy->random = pcur->random->next ,pcur->random->next 刚好就是 7 的 next 节点,也就是新节点 7。这样就连接好了新节点 13 的random指针了。
  5. 下图紫色线条表示 random 指针指向
  6. 第三步,也就是最后一步,断开新节点与原节点的连接,使新节点之间相连。题目中没有要求恢复原链表之间的连接,因此不用管原链表了。断开连接方法:pucr 指针照样遍历原节点,定义 newHead 和 newTail 指针,它们首先指向新节点的头节点,然后循环,先让 pcur 走到下一个原节点,然后修改 newTial 的next指针连接,newTail->next=pcur->next。然后 newTail 往前走,pcur 继续走到下一个原节点。循环结束的条件就是 pcur->next->next == NULL。
  7. 这样新链表就拷贝成功了。

代码:

typedef struct Node Node;//申请新节点
Node* BuyNode(int x)
{Node* newnode = (Node*)malloc(sizeof(Node));newnode->val=x;newnode->next=newnode->random=NULL;return newnode;
}//拷贝新节点
void AddNode(Node* head)
{Node*pcur = head;while(pcur){Node*Next = pcur->next;Node*newnode = BuyNode(pcur->val);pcur->next = newnode;newnode->next = Next;pcur = Next;}
}struct Node* copyRandomList(struct Node* head) 
{if(head==NULL){return NULL;}//1.在原链表上复制新链表AddNode(head);//2.根据原链表为新链表的random指针链接Node*pcur = head;while(pcur){Node*copy = pcur->next;if(pcur->random != NULL){copy->random = pcur->random->next;}pcur=copy->next;}//3.断开连接 pcur = head;Node*newHead,*newTail;newHead = newTail = pcur->next;while(pcur->next->next){pcur=pcur->next->next;newTail->next = pcur->next;newTail = pcur->next;}return newHead;
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构与算法——Java实现 54.力扣1008题——前序遍历构造二叉搜索树

不要谩骂以前的自己 他当时一个人站在雾里也很迷茫 ​​​​​​​ ​​​​​​​ ​​​​​​​—— 24.11.6 1008. 前序遍历构造二叉搜索树 给定一个整数数组&#xff0c;它表示BST(即 二叉搜索树 )的 先序遍历 &#xff0c;构造树并返回其根。 保证 对于给定…

【Qt聊天室客户端】单聊与群聊

1. 区分单聊和群聊 逻辑分析 具体实现逻辑 主窗口完善判断单聊还是群聊的逻辑 单聊会话详情入口中&#xff0c;设置头像和昵称 2. 删除好友 直接找到删除好友的按钮&#xff0c;然后实现其删除逻辑即可 具体实现 无法删除好友BUG处理 问题复现&#xff0c;点击好友删除后&…

1.集合体系补充(1)

1.接口式引用 集合的构造&#xff0c;我们需要采用接口类型引用的的方式&#xff0c;这样做的好处就是方便根据业务或者设计上的变化&#xff0c;快速更换具体的实现。 事实上&#xff0c;Java集合设计体系者也是支持我们这样做的&#xff0c;并且集合体系的设计也是如此的。 创…

枚举及优化(一)

第1题 百钱买百鸡 查看测评数据信息 百钱买百鸡问题&#xff1a;公鸡五文钱一只&#xff0c;母鸡三文钱一只&#xff0c;小鸡三只一文钱&#xff0c;用 100 文钱买 100只鸡&#xff0c;公鸡、母鸡、小鸡各买多少只&#xff1f;本程序要求解的问题是&#xff1a;给定一个正整…

自注意力机制

当输入一系列向量&#xff0c;想要考虑其中一个向量与其他向量之间的关系&#xff0c;决定这个向量最后的输出 任意两个向量之间的关系计算 计算其他向量对a1的关联性 多头注意力机制 图像也可以看成一系列的向量&#xff0c;交给自注意力机制处理&#xff0c;CNN是特殊的自注意…

RabbitMQ的死信队列

1.死信的概念 死信简单理解就是因为种种原因&#xff0c;无法被消费的消息. 有死信自然就有死信队列&#xff0c;消息再一个队列中编程死信之后&#xff0c;它能被重新发送到另一个交换器中&#xff0c;这个交换器就是DLX&#xff0c;绑定DLX的队列&#xff0c;就被称为死信队…

十六 MyBatis使用PageHelper

十六、MyBatis使用PageHelper 16.1 limit分页 mysql的limit后面两个数字&#xff1a; 第一个数字&#xff1a;startIndex&#xff08;起始下标。下标从0开始。&#xff09;第二个数字&#xff1a;pageSize&#xff08;每页显示的记录条数&#xff09; 假设已知页码pageNum&…

SpringBoot框架在共享汽车管理中的应用

3系统分析 3.1可行性分析 通过对本共享汽车管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本共享汽车管理系统采用SSM框架&#xff0c;JAVA作为开发语…

数字化转型助手 快鲸SCRM系统为企业营销赋能

内容概要 在当今这个快速变化的商业环境中&#xff0c;数字化转型已经成为企业生存与发展的关键要素。无论是零售、制造还是服务行业&#xff0c;企业都深刻意识到传统工作模式的局限性&#xff0c;必须借助先进的技术来优化运营和提升客户体验。快鲸SCRM系统就是这样一款数字…

ZooKeeper在kafka集群中有何作用

Zookeeper 存储的 Kafka 信息 &#xff08;1&#xff09;启动 Zookeeper 客户端。 bin/zkCli.sh &#xff08;2&#xff09;通过 ls 命令可以查看 kafka 相关信息。 [zk: localhost:2181(CONNECTED) 2] ls /kafkazk中有一个节点 consumers 这个里面&#xff0c;老版本0.9版…

Linux操作系统:学习进程_对进程概念的深入了解

目录 前言 开篇 一、进程概念 二、进程的描述与管理 1、如何描述与管理 2、Linux中的PCB-task_struct 3、对进程组织的理解 三、进程的属性 1、系统创建进程 2、查看进程 3、进程的标识符 4、退出进程 1>ctrlc 2>kill命令杀死进程 5、用户进程的创建方式…

Embedding 技术在推荐系统中的应用

参考自《深度学习推荐系统》——王喆&#xff0c;用于学习和记录。 介绍 Embedding&#xff0c;中文直译为“嵌入”&#xff0c;常被翻译为“向量化”或者“向量映射”。它的主要作用是将稀疏向量转换成稠密向量&#xff0c;便于上层深度神经网络处理。事实上&#xff0c;Emb…

Kafka面试题

1、kafka消息发送的流程&#xff1f; 在消息发送时涉及到了两个线程&#xff0c;main 线程 和 sender 线程 &#xff0c;在main线程里面创建了一个双端队列&#xff08;RecordAccumulator&#xff09; ,当双端队列里面的信息满足 一定的条件后&#xff0c; sender线程会拉取双端…

RabbitMQ延迟队列(重要)

RabbitMQ延迟队列 1、延迟队列1.1、延迟队列使用场景1.2、延迟队列实现原理 2、使用rabbitmq-delayed-message-exchange 延迟插件2.1、下载2.2、安装2.2.1、解压2.2.2、启用插件2.2.3、查询安装情况 2.4、示例2.4.1、RabbitConfig配置类&#xff08;关键代码&#xff09;2.4.2、…

机器学习—神经网络如何高效实现

深度学习研究人员能够扩展神经网络的原因之一&#xff0c;在过去的十年里建立了非常大的神经网络&#xff0c;是因为神经网络可以向量化&#xff0c;它们可以使用矩阵乘法非常有效的实现&#xff0c;事实证明&#xff0c;并行计算硬件&#xff0c;包括gpus&#xff0c;但也有一…

【数据集】【YOLO】【目标检测】水面船只识别数据集 9798 张,YOLO船只识别算法实战训练教程!

一、数据集介绍 【数据集】水面船只识别数据集 9798 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。 数据集中包含1种分类&#xff1a;{0: ship}&#xff0c;代表水面船只。 数据集来自国内外图片网站和视频截图&#xff1b; 可用于无人机船只检测、监控灯塔船…

斜坡函数功能块(支持正常停机和紧急停机切换)

1、CODESYS斜坡函数功能块 CODESYS斜坡函数功能块(ST源代码)_用plc难能写一个斜坡加减速度吗-CSDN博客文章浏览阅读1k次。本文介绍了如何在CODESYS平台上创建斜坡函数功能块(FC),用于PID闭环控制中的给定值平滑处理。通过ST源代码实现,详细步骤包括仿真测试、变量修改、FC…

渗透测试--web基础之windows(二):常用命令详解及病毒编写

声明&#xff1a;学习素材来自b站up【泷羽Sec】&#xff0c;侵删&#xff0c;若阅读过程中有相关方面的不足&#xff0c;还请指正&#xff0c;本文只做相关技术分享,切莫从事违法等相关行为&#xff0c;本人一律不承担一切后果 目录 一、常见端口对应的服务 二、 常见的cmd命…

【含文档】基于ssm+jsp的客户管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: apache tomcat 主要技术: Java,Spring,SpringMvc,mybatis,mysql,vue 2.视频演示地址 3.功能 管理员登录进入…

腾讯混元宣布大语言模型和3D模型正式开源

腾讯混元大模型正在加快开源步伐。 11月5日&#xff0c;腾讯混元宣布最新的MoE模型“混元Large“以及混元3D生成大模型“ Hunyuan3D-1.0”正式开源&#xff0c;支持企业及开发者精调、部署等不同场景的使用需求&#xff0c;可在HuggingFace、Github等技术社区直接下载&#xff…