面试题链表总结

面试题链表总结

链表定义为:

struct Node
{
    Node():next(nullptr) {};
    Node(int val): value(val), next(nullptr){};
    int value;
    node *next;
}

规定错误处理方式:

  • 如果返回值为指针,返回nullptr
  • 如果返回值为数字,返回为 -1

O(1)删除链表中节点

题目描述: 给出该节点的指针,在链表中删除这个节点

分析:O(1)的复杂度要求, 直接排除遍历的这种情况。只能从自身需求突破,很容易想到,自身删除不易,但删除下一个节点却很容易,所以解法就出来了。(当该节点为最后一个节点的时候,没法办只能遍历了)

代码如下:

void delNode(Node *head, Node *node)
{
    if(node->next)
    {
        Node *tmp = node->next;
        node->value = tmp->value;
        node->next = tmp->next;
        delete(tmp);
    }
    else
    {
        Node *tmp = head;
        while(tmp->next != node)
            tmp = tmp->next;
        tmp->next = nullptr;
        delete(node);
    }
}

翻转单链表

题目描述: 给出链表的头指针,将该链表翻转

分析:这个题目要求是不能申请额外的数组,所以只需要申请两个临时指针,一个记录下一个节点的位置,一个对当前节点进行操作。

代码如下:

Node* reverseList(Node *head)
{
    if(head == nullptr)
        return nullptr;

    Node *tmp = head->next;
    head->next = nullptr;

    Node *res;
    while(tmp)
    {
        res = tmp->next;
        tmp->next = head;
        head = tmp;
        tmp = res;
    }

    return head;
}

链表的倒数第K个

题目描述: 给出链表的头指针,返回链表倒数第K个节点的值

分析:首先想到的是递归到底部,然后向上回溯K-1层即可,这样的做法链表将遍历两次。如果要求只能一次遍历呢?有没有好的方法?面试官这样问的话,好的方法是必然存在的。用两个值,来记录走的位置;首先第一个值走K-1部,那么此时第一个的位置应该是链表的第K个节点。然后两个节点一块进行移动,这样第一个节点到达最后一个节点时,第二个节点的位置,即为倒数第K个节点。

代码如下:


int getLastK(Node *head, int k)
{
    if(k == 0)
        return -1;
    
    int e = 1;
    Node* b = head;

    while(e < k && b)
    {
        b = b->next;
        e ++;
    }
    if(e < k)
        return -1;
    
    while(b->next)
    {
        b = b->next;
        head = head->next;
    }
    return b->value;
}

链表的交点

题目描述:给出两个链表的头指针,返回两个链表相交的节点

分析:两个链表相交类似‘Y’字形;由于两个链表长度不定,所以很难找到相交的位置。所以首先想到,跑出两个链表的长度,然后在根据两个链表的长度差,在跑一下即可找出答案。此时还有一种思路就是两个链表的指针同时走,一个链表的头指针跑到尾部之后再从另一个链表的头部开始跑,最后两个链表会汇到相交的地方。

代码如下:


//一
Node* Intersect(Node* head_x, Node* head_y)
{
    if(head_x == nullptr || head_y == nullptr)
        return nullptr;
    
    auto fun = [](Node *x)->int{
        int res = 0;
        while(x)
        {
            x = x->next;
            res ++;
        }
        return res;
    };

    int x = fun(head_x);
    int y = fun(head_y);
    if(x < y)
    {
        while(y !=  x)
        {
            head_y = head_y->next;
            y --;
        }
    }
    else
    {
        while(y != x)
        {
            head_x = head_x->next;
            x --;
        }
    }

    //检查没有交点的情况
    while(head_x != head_y && head_x)
    {
        head_x = head_x->next;
        head_y = head_y->next;
    }
    return head_x;
}

//二
Node* Intersect(Node* head_x, Node* head_y)
{
    if(head_x == nullptr || head_y == nullptr)
        return nullptr;
    
    Node *a = head_x, *b = head_y;

    //x,y判断没有交点的情况
    bool x = false, y = false;
    while(a != b)
    {
        if(a->next)
            a = a->next;
        else if(x == false)
        {
            x = true;
            a = head_y;
        }
        else
            break;
        
        if(b->next)
            b = b->next;
        else if(y == false)
        {
            y = true;
            b = head_x;
        }
        else
            break;
    }
    if(a != b)
        return nullptr;

    return a;
}

链表环的入口点

题目描述: 给出链表的头指针,返回链表中环的入口点

分析:刚拿到这个题目,如果之前没有做过这种题目,很难想到好的解决方案(大佬不算);
首先引入fast、slow指针,fast指针每次走两步,slow指针每次走一步,那么他们之间的间隔随着步数的增加而增加(每次加一),如果存在环,那么这两个指针必然会在某个时刻相遇(他们之间的间隔为环大小的整数倍)。记录一下这个相遇点(在环内),然后接着走,再次回到这个相遇点就能得到环的长度; 然后还是用两个指针,一个指针先走环的长度的长度,然后两个指针同时走, 第一次相遇的地方即为环的入口

代码如下:

Node* getRingGate(Node *head)
{
    if(head == nullptr || head->next == nullptr)
        return nullptr;
    
    Node *fast=head->next->nxet, *slow = head->next;
    while(fast != slow)
    {
        slow = slow->next;
        if(fast && fast->next)
            fast = fase->next->next;
        else
            return nullptr;
    }

    Node *tmp = slow;
    slow = slow->next;
    int size = 1;
    while(slow != tmp)
    {
        slow = slow->next;
        size ++;
    }

    fast = slow = head;
    while(size)
    {
        fast = fast->next;
        size --;
    }

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

    return fast;
}
posted @ 2017-10-19 22:16  aiterator  阅读(303)  评论(0编辑  收藏  举报