算法通关村第二关——指定区间反转和两两交换反转问题解析

指定区间反转

将上图letfpos=2,rightpos=4,将这两个位置区间反转,也就是蓝色区间的链表反转。

该问题解法也可分为头插和穿针引线

头插法

头插法可以实现链表反转,那么首先要找到插入的头在哪,观察上图可发现,他们都是在node(1)之后进行链表操作的,所以像上图的头结点就可以看做是node(1)。

要记住,所谓头插法,不是一定要在整个链表的头部插入,而是在要反转的链表的头结点(就是首结点的前驱结点)插入。

但是还有可能它就是让从整个链表的第一个结点进行反转,leftpos=1,那么这会虚拟结点就派上用了,它可以让众结点平等,不论是原链表的第一个结点还是其他结点都会被视为统一。

因为虚拟结点就当做此时链表的第一个结点,后面所有结点都不再是第一个结点,就不会有插入在头结点还是中间结点的情况了。

找到该头结点可以用for(i=1; i<=left-1; i++)来找到。

再观察上图可发现,每有一个新结点插入时,node(2)总是在这串反转链表的最后一个,所以node(2)可以一直连在链表中,有个妙招就是让node(2)连在一下要反转的结点的下一个结点,也就是node(2)=node(2)->next->next; 这样可以确保node(2)不会丢失。

除了node(2)要操作(right-left)个元素,所以这个当做循环条件。当操作最后一个要反转的元素时,node(2)可以刚好与原链表接上,这个想法真的很巧妙,拓宽了我的思路。

代码如下:

struct ListNode *reverseBetween1(struct ListNode *head, int left, int right)
{
    //虚拟结点
    struct ListNode *newhead=(struct ListNode*)malloc(sizeof(struct ListNode));
    newhead->next=head;
    //p为反转链表的头结点
    struct ListNode *p=newhead;
    for(int i=1;i<=left-1;i++)
        p=p->next;
    //node1为要与原链表相连的结点,该结点一直在反转链表的末尾
    struct ListNode *node1=p->next;
    
    for(int i=1;i<=right-left;i++)
    {
        //node2为需要操作的结点
        struct ListNode *node2=node1->next;
        //操作之前先将node1连在链表上,也就是下下个结点
        node1->next=node2->next;
        //操作node2,头插法node2
        node2->next=p->next;
        p->next=node2;
    }
    return newhead->next;
}

穿针引线法

穿针引线法则不依赖结点实现链表反转

由于没有依赖别的结点,所以需要先将要反转的链表单独取下来,然后穿针引线法实现反转。

反转后,将反转的链表与原链表相连,所以这里我们需要先记录一下要连接的前驱pre与后继succ。

之后指针连接,pre->next=right; left->next=succ;

struct ListNode *reverseBetween2(struct ListNode *head, int left, int right)
{
    //同样虚拟结点,众生平等
    struct ListNode *dummyNode = (struct ListNode *)malloc(sizeof(struct ListNode));
    dummyNode->next = head;
    struct ListNode *pre = dummyNode;

    //找到前驱
    for (int i = 1; i <= left - 1; i++)
    {
        pre = pre->next;
    }
    //定义右节点
    struct ListNode *rightNode = pre;
    //找到右节点
    for (int i = 1; i <= right - left + 1; i++)
    {
        rightNode = rightNode->next;
    }
    //左结点
    struct ListNode *leftNode = pre->next;
    //后继结点
    struct ListNode *succ = rightNode->next;

    //取出区间链表
    pre->next = NULL;
    rightNode->next = NULL;

    //穿针引线法反转链表
    reverseLinkedList(leftNode);

    //将反转链表与链表接上
    pre->next = rightNode;
    leftNode->next = succ;

    return dummyNode->next;
}

两两交换链表结点

同样先创建虚拟结点,众点平等

两两交换相当于反转两个结点,头插法方便一些。直接头结点连到第二个结点                          demmy->next=node2,第一个结点连到第二个结点的后继node1->next=node2-->next,第二个结点连第一个结点node2->next=node1

注意顺序不能反,如果先node2->next=node1; node2的后继就会改变为node1,node1就无法连到node2的后继

当连完后,要记得记录下一组的头结点即node1

当然可以看做循环n组反转2个元素,那么循环条件为 node->next!=NULL&&node->next->next!=NULL,后一个条件是防止只剩一个元素,剩一个元素就不用反转了

代码如下:

  struct ListNode * swapPairs(struct ListNode * head)
{
    struct ListNode *dummyHead = (struct ListNode *)malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    //temp为反转时的头结点
    struct ListNode *temp = dummyHead;

    //反转元素
    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 dummyHead->next;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
yolo-v5系列算法是一种基于深度学习的目标检测算法,其通过将输入图像划分为一系列网格单元,并对每个单元预测出目标的类别和边界框,从而实现对图像中目标的检测和定位。 模型移植是指将训练好的yolo-v5模型从一个平台或框架移植到另一个平台或框架的过程。在实际应用中,由于硬件设备或软件平台的限制,往往需要将模型移植到适用于特定平台的框架上,以便进行推理和应用。 模型移植的主要步骤包括模型导出、模型转换和模型部署。首先,需要将yolo-v5模型导出为通用的模型文件,例如ONNX或TensorFlow格式。然后,利用模型转换工具将导出的模型文件转换为目标平台所支持的模型格式,如Tensorflow Lite或Caffe等。最后,将转换后的模型部署到目标平台上,以便进行推理和应用。 模型移植的问题是确保模型在移植过程中的准确性和效率。为了保持模型的准确性,需要注意模型转换过程中参数的正确性和一致性。同时,还需要针对目标平台的硬件设备和软件框架进行优化,以提高模型在目标平台上的推理速度和性能。 总而言之,yolo-v5系列算法的模型移植是将训练好的模型从一个平台移植到另一个平台的过程。通过合理的模型导出、转换和部署步骤,可以将yolo-v5模型应用于不同的硬件设备和软件平台,以实现目标检测和定位的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值