LeetCode-返回链表倒数第K个节点、链表的回文结构,相交链表

一、返回链表倒数第k个节点

. - 力扣(LeetCode)

 本体思路参展寻找中间节点的方法,寻找中间节点是定义快慢指针,快指针每次走两步,慢指针每次走一步,当快指针为空或者快指针的下一个节点是空时,此时的慢指针指向的节点就是中间节点;并且此时的快指针和慢指针之间的节点个数就是整个链表的一半;

据此同理,可以定义快慢指针,使得快指针走到尾的时候,与慢指针之间的差距恰好是k个节点,那么此时的慢指针就是题中要求的节点;

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


int kthToLast(struct ListNode* head, int k){
   struct ListNode* slow=head,*fast=head;

    while(k--)
    {
        fast=fast->next;
    }

    while(fast)
    {
        slow=slow->next;
        fast=fast->next;
    }
    return slow->val;
}

二、链表的回文结构

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

 回文结构即使对称的;本题思路是先利用快慢指针找到中间节点,之后再从中间节点开始逆置此节点之后的链表,得到一条新的链表;之后再从原本的链表的头节点和这条新链表的头节点开始一一比较,若是val值都相同则说明这个链表是回文结构;

当链表是奇数个时,新链表多出一个节点,但是不影响代码的正常运行,因为原链表中中间节点的前一个节点的指向还是新链表中作为尾节点的之前的中间节点,新链表的倒数第二个指针指向的也是这个节点,所以最后一次循环的时候其实是同一个节点在比较。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        // write code here
        //找到中间节点
        ListNode* slow=A;
        ListNode* fast=A;
        while(fast && fast->next)
        {
            slow=slow->next;
            fast=fast->next;
        }
        ListNode* mid=slow;

        //对从中间节点向后的节点组成的链表进行逆置操作
        ListNode* newhead=NULL;
        ListNode* cur=mid;   
        while(cur)
        {
            ListNode* next=cur->next;
            cur->next=newhead;
            newhead=cur;
            cur=next;
        }

        //开始从头比较,若是都相等,那么就是回文结构
        ListNode* head=A;
        while(head && newhead)
        {
            if(head->val!=newhead->val)
            {
                return false;
            }
            head=head->next;
            newhead=newhead->next;
        }
        return true;
    }
};

三、相交链表

. - 力扣(LeetCode)

 

 本题思路:首先判断两条链表是否相交,只需要判断尾节点的地址是否相同就行了,因为当两条链表相交时,无论从哪个节点开始相交起,尾节点的地址一定相同;反之,若是尾节点的地址不相同,那么这两条链表一定不相交;

在已经知道了两条链表相交的情况下如何寻找开始相交的节点?先计算出两条链表的长度,再计算出长度差,之后让长的链表先走这个长度差的节点,此时长的链表和短的链表之后的节点个数就相同了,此时开始一起遍历长链表和短链表,在遍历过程中若长链表和短链表的某一个节点的地址相同,就跳出循环,此时的节点就是开始相交的节点;

注意本题的比较不能用val值,因为两条链表中不同的地址的节点可能含有相同的val值;这时会造成混淆。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if(headA==NULL || headB==NULL)
    {
        return NULL;
    }

    struct ListNode* tailA=headA;
    struct ListNode* tailB=headB;
    int lenA=1;
    int lenB=1;
    while(tailA->next)
    {
        tailA = tailA->next;
        lenA++;
    }
    while(tailB->next)
    {
        tailB = tailB->next;
        lenB++;
    }
    if(tailA!=tailB)
    {
        return NULL;
    }

    int gap=abs(lenA-lenB);

    struct ListNode* longlist=headA;
    struct ListNode* shortlist=headB;//先假设A更长
    if(lenB>lenA)
    {
        longlist=headB;
        shortlist=headA;
    }//若是B长就进入该语句,改变更长链表指向的对象,反之则假设成立
    
    while(gap--)
    {
        longlist=longlist->next;
    }
    while(longlist != shortlist)
    {
        longlist=longlist->next;
        shortlist=shortlist->next;
    }
    return longlist;
}

LeetCode 234题回文链表有多种解法,以下为你介绍几种常见的解法: ### 解法一:将链表复制到数组里再从两头比对 将链表元素复制到数组中,然后使用双指针从数组的两端向中间遍历,比较对应元素是否相等。如果在遍历过程中发现不相等的元素,则链表不是回文链表;如果遍历完整个数组都没有发现不相等的元素,则链表是回文链表。 ```cpp #include <vector> class Solution { public: bool isPalindrome(ListNode* head) { std::vector<int> listvec; // 把链表中元素都插入数组 while (head != nullptr) { listvec.push_back(head->val); head = head->next; } // 一个迭代器从头,一个迭代器从尾 auto it_head = listvec.begin(); auto it_back = listvec.end() - 1; // 若迭代器相遇了则说明都检查完了,可以返回true while (it_back - it_head > 0) { // 检查到值不相等就返回false if ((*it_head++) != (*it_back--)) return false; } return true; } }; ``` ### 解法二:递归法 递归地遍历链表,同时使用一个指针从链表头开始比较。递归过程中,先递归到链表的末尾,然后在回溯的过程中与链表头指针指向的元素进行比较。 ```cpp class Solution { ListNode* frontPointer; public: bool recursivelyCheck(ListNode* currentNode) { if (currentNode != nullptr) { if (!recursivelyCheck(currentNode->next)) { return false; } if (currentNode->val != frontPointer->val) { return false; } frontPointer = frontPointer->next; } return true; } bool isPalindrome(ListNode* head) { frontPointer = head; return recursivelyCheck(head); } }; ``` ### 解法三:快慢指针 + 反转链表 使用快慢指针找到链表的中点,然后将链表的后半部分反转,最后比较前半部分和反转后的后半部分是否相等。 ```cpp class Solution { public: bool isPalindrome(ListNode* head) { if (head == nullptr) return true; // 找到前半部分链表的尾节点并反转后半部分链表 ListNode* firstHalfEnd = endOfFirstHalf(head); ListNode* secondHalfStart = reverseList(firstHalfEnd->next); // 判断是否回文 ListNode* p1 = head; ListNode* p2 = secondHalfStart; bool result = true; while (result && p2 != nullptr) { if (p1->val != p2->val) result = false; p1 = p1->next; p2 = p2->next; } // 还原链表返回结果 firstHalfEnd->next = reverseList(secondHalfStart); return result; } private: ListNode* reverseList(ListNode* head) { ListNode* prev = nullptr; ListNode* curr = head; while (curr != nullptr) { ListNode* nextTemp = curr->next; curr->next = prev; prev = curr; curr = nextTemp; } return prev; } ListNode* endOfFirstHalf(ListNode* head) { ListNode* fast = head; ListNode* slow = head; while (fast->next != nullptr && fast->next->next != nullptr) { fast = fast->next->next; slow = slow->next; } return slow; } }; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值