【链表面试题】【进阶】

版权声明: https://blog.csdn.net/qq_41880190/article/details/85110546

1、查找倒数第 k 个链表


题目描述:给定一个单向链表 List ,要你设计算法找出倒数第 K 个结点并打印

struct ListNode
{
    DataType m_Value;
    ListNode* m_pNext;
};
ListNode* FindKthToTail(ListNode* pHead);

首先我自己的思路:




1、首先我们能想到的是假如给定的是一个双向链表就好了,我们可以从链表的尾部向前遍历找到倒数第 K 个结点,但是对于我们这道题显然是行不通的

2、根据链表的特性我们能想到的是,链表节点数假设为 n ,要找倒数第 K 个结点,则我们只需从前往后遍历链表,走 (n - k + 1) 步就可以得到倒数第 K 个结点;至于链表总结点数,我们可以遍历链表得出::为了实现只遍历一次链表就得到倒数第 K 个结点,我们可以定义两个指针第一个指针从头节点遍历走 (k - 1) 步,从第 K 步开始两个指针同步向后遍历,当快指针到达链表的尾节点是,慢指针刚好是倒数第 K 个结点;基于这种思路我们可以写出简单的代码;如下:


#include "SList.h"

/*
* struct ListNode
{
    DataType m_Value;
    ListNode* m_pNext;
};
*/
ListNode* FindKthToTail(ListNode* pHead, unsigned int k)
{
    if(pHead == nullptr || k == 0)
        return nullptr;
    ListNode* pFast = pHead;
    ListNode* pSlow = pHead;
    while(--k && pFast->m_pNext != nullptr)
        pFast = pFast->m_pNext;
    while(pFast->m_pNext != nullptr)
    {
        pFast = pFast->m_pNext;
        pSlow = pSlow->m_pNext;
    }
    cout << pSlow->m_Value << endl;
    return pSlow;
}

void FindKthToTailTest()
{
    cout << ">>查找链表倒数第 K 个结点" << endl;
    ListNode* pHead;
    SListInit(&pHead);
    SListPushBack(&pHead, 1);
    SListPushBack(&pHead, 2);
    SListPushBack(&pHead, 4);
    SListPushBack(&pHead, 7);
    SListPushBack(&pHead, 3);
    SListPushBack(&pHead, 5);
    SListPushBack(&pHead, 9);
    SListPushBack(&pHead, 8);
    SListPushBack(&pHead, 12);
    cout << "倒数第 3 个结点 : " << FindKthToTail(pHead, 3) << endl;
    SListPrint(pHead);
}
int main()
{
    FindKthToTailTest();
    return 0;
}

运行结果:

解答这道题需注意的是:

1、输入的链表为空

2、链表总结点数少于 K 或者链表的总结点数 K== 0 

优化后的代码为:

#include "SList.h"

/*
* struct ListNode
{
    DataType m_Value;
    ListNode* m_pNext;
};
*/

ListNode* __FindKthToTail(ListNode* pHead, unsigned int k)
{
    if(pHead == nullptr || k == 0)
        return nullptr;
    ListNode* pFast = pHead;
    ListNode* pSlow = pHead;
    for(unsigned int i = 0; i < k-1; ++i)
    {
        if(pFast->m_pNext != nullptr)
        {
            pFast = pFast->m_pNext;
        }
        else
        {
            return nullptr;
        }
    }
    while(pFast->m_pNext != nullptr)
    {
        pSlow = pSlow->m_pNext;
    }
    return pSlow;
}

void __FindKthToTailTest()
{
    cout << ">>优化版本:" << endl;
    cout << ">>查找链表倒数第 K 个结点:" << endl;
    ListNode* pHead;
    SListInit(&pHead);
    SListPushBack(&pHead, 1);
    SListPushBack(&pHead, 2);
    SListPushBack(&pHead, 4);
    SListPushBack(&pHead, 7);
    SListPushBack(&pHead, 3);
    SListPushBack(&pHead, 5);
    SListPushBack(&pHead, 9);
    SListPushBack(&pHead, 8);
    SListPushBack(&pHead, 12);
    cout << "倒数第 3 个结点 : " << __FindKthToTail(pHead, 3) << endl;
    SListPrint(pHead); 
}
int main()
{
    //FindKthToTailTest();
    __FindKthToTailTest();
    return 0;
}
#include "SList.h"

/*
* struct ListNode
{
    DataType m_Value;
    ListNode* m_pNext;
};
*/

ListNode* __FindKthToTail(ListNode* pHead, unsigned int k)
{
    if(pHead == nullptr || k == 0)
        return nullptr;
    ListNode* pFast = pHead;
    ListNode* pSlow = pHead;
    for(unsigned int i = 0; i < k-1; ++i)
    {
        if(pFast->m_pNext != nullptr)
        {
            pFast = pFast->m_pNext;
        }
        else
        {
            return nullptr;
        }
    }
    while(pFast->m_pNext != nullptr)
    {
        pSlow = pSlow->m_pNext;
    }
    return pSlow;
}

void __FindKthToTailTest()
{
    cout << ">>优化版本:" << endl;
    cout << ">>查找链表倒数第 K 个结点:" << endl;
    ListNode* pHead;
    SListInit(&pHead);
    SListPushBack(&pHead, 1);
    SListPushBack(&pHead, 2);
    SListPushBack(&pHead, 4);
    SListPushBack(&pHead, 7);
    SListPushBack(&pHead, 3);
    SListPushBack(&pHead, 5);
    SListPushBack(&pHead, 9);
    SListPushBack(&pHead, 8);
    SListPushBack(&pHead, 12);
    cout << "倒数第 3 个结点 : " << __FindKthToTail(pHead, 3) << endl;
    SListPrint(pHead); 
}
int main()
{
    //FindKthToTailTest();
    __FindKthToTailTest();
    return 0;
}

2、反转链表


扫描二维码关注公众号,回复: 4671822 查看本文章


ListNode* ReverseList(ListNode* pHead)
{
    if(pHead == NULL)
    {
        return NULL;
    }
    if(pHead->next == NULL)
    {
        return pHead;
    }
    ListNode* pCur = pHead->next;
    ListNode* pPrev = pHead;
    ListNode* pNext = pCur->next;
    while(pCur->next)
    {
        pNext = pCur->next;
        pCur->next = pPrev;
        pPrev = pCur;
        pCur = pNext;
    }
    pCur->next = pPrev;
    //最后一个节点的指向它的前驱
    pHead->next = NULL;
    //最后一个结点的下一个结点置 NULL
    return pCur;
}

栈实现

ListNode* ReverseList(ListNode* pHead)
{
    if (pHead == nullptr || pHead->next == nullptr)
    {
        return pHead;
    }
    stack<ListNode*> node;
    ListNode* pCur = pHead;
    while(pCur->next)    //链表不为空入栈
    {
        node.push(pCur);
        pCur = pCur->next;
    }
    ListNode* pReversedNode = pCur;    //反转后新链表的头节点就是栈顶元素
    while(!node.empty())
    {
        pCur->next = node.top();
        pCur = pCur->next;
        node.pop();
    }
    pCur->next = NULL;
    return pReversedNode;
}

递归实现

ListNode* ReverseList(ListNode* pHead)
{
    if(pHead == NULL || pHead->next == NULL)
        return pHead;
    ListNode* pReversedNode = ReverseList(pHead->next);
    pHead->next->next = pHead;    //反转节点
    phead = NULL;    //第一个节点反转后置下一个为 NULL
    return pReversedNode;
}

从尾到头打印链表

递归实现


void ReverseList(ListNode* pHead)
{
    if(pHead != NULL)
    {
        if(pHead->next != NULL)
        {
            ListNode* pReversedNode = ReverseList(pHead->next);
        }
        cout << pReversedNode->data;
    }
}

 

栈实现


j仅仅打印链表的值,不修改链表结构

先遍历链表,再打印

void ReverseList(ListNode* pHead)    //先进后出利用栈的特性
{
    if(pHead == NULL || pHead->next == NULL);
        return phead;
    stack<ListNode*> node;    
    ListNode* pCur = pHead;
    while(pCur->next)    //pCur 一直遍历直到 pCur->next == NULL,入栈结束
    {
        node.push(pCur);
        pCur = pCur->next;
    }
    while(!node.empty())    //栈不为空,pop 出栈并且打印
    {
        pCur = node.top();
        cout << pCur->data;
        node.pop();
    }
}

 

3、找出给定链表的公共结点


题目描述:给定两个链表,找出它们的第一个公共节点::分三步

1、分别计算两个链表的长度

2、比较出较长的那一个链表,长出多少,较长的链表从头开始向后遍历多少步

3、找公共节点(找第一个公共结点、ps:找出现的公共结点)


代码如下:SList.h


/*************************************************************************
	> File Name: SList.h
	> Author: 
	> Mail: 
	> Created Time: Tue Oct 23 20:19:58 2018
 ************************************************************************/

#pragma once

#include <iostream>

using namespace std;

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;

//节点结构体
typedef struct ListNode
{
    DataType m_Value;
    struct ListNode* m_pNext;
}ListNode;
//查找,找到了返回地址,没有找到返回NULL

ListNode* SListFind(ListNode* p, DataType data)//不改变链表的值,为 ListNode*
{
    ListNode* cur = p;
    for(cur = p; cur != NULL; cur = cur->m_pNext)
    {
        if(cur->m_Value == data)
        {
            return cur;//返回地址
        }
    }
}
/*
void SListInsert(ListNode* *p,ListNode* pos, DataType m_Value)
{
    if(*p == pos)
    {
        SListPushFront(p, m_Value);
        return;
    }
    ListNode* newNode = CreatNode(m_Value);
    ListNode* cur = *p;
    while(cur->m_pNext != pos)
    {
        cur->m_pNext = newNode;
        newNode->m_pNext = pos;
        cur = cur->m_pNext;
    }


}
*/
void SListInit(ListNode* *p)
{
    assert(p != NULL);
    *p = NULL;

}
void SListDestroy(ListNode* *p)
{
    assert(p != NULL);

}
static ListNode* CreatNode(DataType m_Value)
{
    ListNode* pNode = (ListNode *)malloc(sizeof(ListNode));
    pNode->m_Value = m_Value;
    pNode->m_pNext = NULL;
    return pNode;
}
//尾删
void SListPopBack(ListNode* *p)
{
    assert(p != NULL);
    assert(*p != NULL);//判断链表是否为空
    if((*p)->m_pNext == NULL)
    {
        free(p);
        p = NULL;
        return ;
    }
    //链表中至少有两个
    ListNode* cur = *p;
    while(cur->m_pNext != NULL)
    {
        //free(cur->m_pNext);
        cur = cur->m_pNext;
    }
    free(cur->m_pNext);
    cur->m_pNext = NULL;
}
//头删

//尾插
void SListPushBack(ListNode* *p, DataType m_Value)
{
    ListNode* pNode = CreatNode(m_Value);/* 申请节点,赋值且插入 */
    assert(p != NULL);//传入地址不为空
    if(*p == NULL)/* 链表为空 */
    {
        *p = pNode;
        return ;
    }
    //找链表中的最后一个节点
    //ListNode* pNode = CreatNode(m_Value);//申请节点,赋值且插入
    ListNode* cur = *p;
    while(cur->m_pNext != NULL)
    {
        cur = cur->m_pNext;
    }
    cur->m_pNext = pNode;
}
//头插
void SListPushFront(ListNode* *p, DataType m_Value)
{
    assert(p != NULL);
    //assert(*p != NULL);
    ListNode* pNode = (ListNode *)malloc(sizeof(ListNode));
    pNode->m_Value = m_Value;
    pNode->m_pNext = NULL;
    //pNode->m_pNext = *p;
    *p = pNode;
}

void SListPrint(ListNode* p)
{
    ListNode* cur = p;
    while(cur != NULL)
    {
        printf("%d ", cur->m_Value);
        cur = cur->m_pNext;
    }
    printf("\n");
}

void SListTest()
{
    ListNode* pFirst;

    SListInit(&pFirst);//初始化
    //链表头插
    //SListPushFront(&pFirst, 0);
    SListPushFront(&pFirst, 1);
    SListPushFront(&pFirst, 2);
    SListPushFront(&pFirst, 3);
    SListPushFront(&pFirst, 4);
    SListPushFront(&pFirst, 5);
    SListPrint(pFirst);
    //链表尾插
    SListPushBack(&pFirst, 4);
    SListPushBack(&pFirst, 3);
    SListPushBack(&pFirst, 2);
    SListPushBack(&pFirst, 1);
    SListPrint(pFirst);//打印尾插之后的链表
    SListPopBack(&pFirst);
    SListPopBack(&pFirst);
    SListPopBack(&pFirst);
    SListPrint(pFirst);
    //SListInsert();
    //CreatNode(m_Value);


}
ListNode* SList(ListNode* pHead1)
{
    //if(pHead == pHead1)
    //{
    SListInit(&pHead1);
    SListPushBack(&pHead1, 0);
    SListPushBack(&pHead1, 1);
    SListPushBack(&pHead1, 2);
    SListPushBack(&pHead1, 3);
    SListPushBack(&pHead1, 4);
    SListPushBack(&pHead1, 5);
    SListPushBack(&pHead1, 6);
    SListPushBack(&pHead1, 7);
    SListPushBack(&pHead1, 8);
    SListPushBack(&pHead1, 9);
    //return pHead1;
    //}
    /*
    else
    {
        ListNode* pHead2;
        SListInit(&pHead2);
        SListPushFront(&pHead2, 0);
        SListPushFront(&pHead2, 1);
        SListPushFront(&pHead2, 2);
        SListPushFront(&pHead2, 3);
        SListPushFront(&pHead2, 4);
        SListPushFront(&pHead2, 5);
        SListPushFront(&pHead2, 6);
        SListPushFront(&pHead2, 7);
        SListPushFront(&pHead2, 8);
        SListPushFront(&pHead2, 9);
    }*/
    return pHead1;
}

找公共结点函数:FindSameNode.cpp

/*
struct ListNode {
	int data;
	struct ListNode *next;
};*/

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        if(pHead1 == nullptr || pHead2 == nullptr)
            return nullptr;
        size_t len1 = 0;
        size_t len2 = 0;
        ListNode* pCur1 = pHead1;
        ListNode* pCur2 = pHead2;
        //获取链表长度
        while(pCur1)
        {
            
            pCur1 = pCur1->next;
            len1++;
        }
        while(pCur2)
        {
            
            pCur2 = pCur2->next;
            len2++;
        }
        pCur1 = pHead1;
        pCur2 = pHead2;
        //比较哪一个链表较长
        size_t sublen = 0;
        if(len1 < len2)
        {
            sublen = len2 - len1;
            while(sublen--)
                pCur2 = pCur2->next;
        }
        
        if(len1 > len2)
        {
            sublen = len1 - len2;
            while(sublen--)
                pCur1 = pCur1->next;
        }
        //找公共结点
        while(pCur1 != nullptr && pCur2 != nullptr)
        {
            if(pCur1 == pCur2)
                break;
            pCur1 = pCur1->next;
            pCur2 = pCur2->next;
        }
        return pCur1;
    }
};

 

 

 

 

猜你喜欢

转载自blog.csdn.net/qq_41880190/article/details/85110546