链表相关oj题 二

 

目录

 一、分隔链表

二、链表的回文结构

三、相交链表

 四、环形链表


 一、分隔链表

86. 分隔链表https://leetcode-cn.com/problems/partition-list/题目:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。你应当 保留 两个分区中每个节点的初始相对位置。

图解:

 代码:

struct ListNode* partition(struct ListNode* head, int x)
{
    //新建立俩个链表,链表1为less(放小于x的值),链表2为greater(放大于等于x的值)
    //链表1设立一个头指针lesshead和一个尾指针lesstail
    //链表2设立一个头指针greaterhead和一个尾指针greatertail
    //然后分别在设立一个头结点哨兵位,因为我们要进行尾插
    //如果没有哨兵位我们就要进行头指针为NULL的情况的判定,第一次要将头指针指向第一个节点,
    //而后面迭代的是将后一个节点放入前一个节点的next里面,所以多一次判断
    //但是如果有哨兵位我们就可以直接进行迭代,每次直接放入next区域
    struct ListNode* less = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* greater = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* lesshead,*lesstail,* greaterhead,*greatertail;
    lesshead = lesstail = less;
    lesstail->next = NULL;
    greaterhead = greatertail = greater;
    greatertail->next= NULL;
    struct ListNode* cur =head;
    //进行初始链表中遍历
    while(cur)
    {   
        //进行判断<x的情况,放入less链表中
        if(cur->val < x)
        {
            lesstail->next = cur;
            lesstail = cur;
        }
        else
        {
            greatertail->next = cur;
            greatertail = cur;
        }
        cur = cur->next;
    }
    //将lesstail链接greaterhead节点的下一个节点
    lesstail->next = greater->next;
    //将greater链表的最后一个位置赋为NULL;因为最后一个位置可能链接到的是原链表中他的后一个节点
    greatertail->next = NULL;
    //保存less链表哨兵位的后一个节点,因为哨兵位不存值
    struct ListNode* newhead = lesshead->next;
    //释放开辟的内存
    free(less);
    free(greater);
    //返回的应该是less节点的下一个节点
    return newhead;
}

运行结果:

 牛客网类似题目:几乎相同(可以再写一遍,练练手)

链表分割_牛客题霸_牛客网 (nowcoder.com)

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) 
    {
        //1.建立俩个链表less ,greater 小于x的链接到less,大于或等于less链接到greater
        //2.将greater链接到less之后
        //建立一个哨兵位
        ListNode* less = (ListNode*)malloc(sizeof(struct ListNode));
        ListNode* greater = (ListNode*)malloc(sizeof(struct ListNode));
        ListNode* lesshead  = less;
        ListNode* lesstail  = less;
        ListNode* greaterhead  = greater;
        ListNode* greatertail  = greater;
        while(pHead)
        {
            if(pHead->val < x)
            {
                lesstail->next = pHead;
                lesstail = pHead;
            }
            else
            {
                greatertail->next = pHead;
                greatertail = pHead;
            }
            
            pHead = pHead->next;
        }
        greatertail->next = NULL;
        lesstail->next = greaterhead->next;
        ListNode* phead = less->next;
        free(less);
        less = NULL;
        free(greater);
        greater = NULL;
        return phead;
    }
   
    
};

运行结果:

二、链表的回文结构

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

题目:

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

图解分析:

代码:

#include<stdio.h>
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/

//寻找中间节点
    struct ListNode* MiddleNode(struct ListNode* fast,struct ListNode* slow)
{
        //奇数和偶数继续的情况
       while(fast != NULL && fast->next != NULL)
       {
           slow = slow->next;
           fast = fast->next->next;
       }
        return slow;
}
    
//逆置
    struct ListNode* Inverse(struct ListNode* middle)
    {
        struct ListNode* tail = NULL;
        struct ListNode* cur = middle;
        struct ListNode* prev =NULL;
        while(cur)
        {
         tail = cur->next;
         cur->next = prev;
         prev = cur;
         cur = tail;
        }
        return prev;
    }
    
//比较
    bool cmp(struct ListNode* A,struct ListNode* head)
    {
       while(A && head)
       {
            if(A->val== head->val)
        {
            A =  A->next;
            head = head->next;
        }
        else
        {
            return false;
        }
       }
        return true;
    }

class PalindromeList {
public:
    
    bool chkPalindrome(ListNode* A) 
    {
        //1.找到中间节点,然后将中间节点及之后的节点逆置
        //2.结束条件:指针为NULL
        
        //找到中间节点(快慢指针:一步俩步)
        ListNode* fast = A;
        ListNode* slow = A;
        struct ListNode* middle = MiddleNode(fast,slow);
        //将中间节点以及之后的节点逆置
        struct ListNode* head = Inverse(middle);
        bool ret = cmp(A,head);
        return ret;
    }
};

运行结果:

 相关内容练习:

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

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

解析:

链表相关oj题 一_迷茫中的小伙的博客-CSDN博客

三、相交链表

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

题目:给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

 思路一:1.判断是否有相同的节点,即尾指针是否相同,相同则有相交,不同则没有相交,因为如果有相交,那么是因为第一个相同节点只有一个next,不可能再分出俩个链表出来

            2. 如果俩个链表长度相同,那么对应着就很好比较,所以分别记录他们的长度,之后让长的链表先走他们相差的节点,走到他们节点个数相同,然后进行比较,不同则往后走while(longList

!= shortList)则都往后走一个节点。最后返回他们相同的节点

时间复杂度 o(n)

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
    //判断他们是否有共同的节点即判断尾结点是否相同
    struct ListNode * tailA = headA;
    struct ListNode * tailB = headB;
    int lengthA = 1;//因为最后一个节点不会算上,所以初始值要从1开始
    int lengthB = 1;
    //寻找尾
    while(tailA->next)
    {
        lengthA++;
        tailA = tailA->next;
    }
      while(tailB->next)
    {
        lengthB++;
        tailB = tailB->next;
    }
    //判断尾指针是否相同
    //没有相交
    if(tailA != tailB)
    {
        return NULL;
    }
    // 有相交
    else
    {
        //思路一:
        //重置tailA和tailB
        tailA = headA;
        tailB = headB;
        int count = lengthB -lengthA;
        if(lengthA < lengthB)
        {
            
            while(count--)
            {
                tailB = tailB->next;
            }
        }
         else
        {
            count = lengthA -lengthB;
            while(count--)
            {
                tailA = tailA->next;
            }
        }
        while(tailA)
        {
            if(tailA == tailB)
            {
                return tailA; 
            }
            else
            {
                 tailA = tailA->next;
                 tailB = tailB->next;
            }
        }
         //  有相交并且此时长度相同
        // 比较指针地址是否相同
        // 只要headA不等于headB就往后走
        //     while(tailA != tailB)
        // {
            
        //     tailA = tailA->next;
        //     tailB = tailB->next;
            
        // }
}
    return tailA;//必须要再次返回tailA

        //思路二:
    //     int count = abs(lengthA- lengthB);
    //     //就假设headA为长的链表,headB为短链表
    //     struct ListNode* longList = headA;
    //     struct ListNode* shortList = headB;
    //     if(lengthA < lengthB)
    //     {
    //         longList = headB;
    //         shortList = headA;
    //     }
    //    while(count--)
    //    {
    //        longList = longList->next;
    //    }
    //    while(longList != shortList)
    //    {
    //        longList = longList->next;
    //        shortList = shortList->next;
    //    }
    //    return longList;
}

运行结果:

 思路二:暴力求解o(n²)

将headA的每一个节点与headB比较,headB比完所有节点,headA指向下一个节点,知道headA比较完。

代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode* ret = NULL;
    struct ListNode* temp = headB;
    //暴力求解O(N平方)
    while(headA)
    {
        while(headB)
        {
            if(headA == headB)
            {
                ret =  headA;
                break;
            }
            else
            {
                headB = headB->next;
            }
        }
        if(ret != NULL)
        {
            break;
        }
        headB = temp;
        headA = headA->next;
        
    }
    return ret;
}

运行结果:

 四、环形链表

141. 环形链表 - 力扣(LeetCode) (leetcode-cn.com)

题目:给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。

图解分析:

 代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) 
{
        //快慢指针fast,slow
        struct ListNode* fast = head;
        struct ListNode* slow = head;
        //fast走俩步,slow走一步
        //起始:fast走俩步进环
        //中间:slow进环,fast开始追slow
        //结束:fast追上slow
        //带环:fast 就会追上slow
        //不带环:fast 就会为NULL
        while(fast && fast->next)//奇数和偶数的情况
        {
          
            fast = fast->next->next;
            slow = slow->next;
            //如果放在上面那么就是头结点他们相等了,所以要让他们先跑起来再去看看他们是否会有重合
            if(fast == slow)
            {
                return true;
            }
        }
        return false;
}

运行结果:

 

本篇为链表相关oj题,如有问题请评论区多多评论,共同学习^_^

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值