您的位置:首页 > 其它

链表

2016-07-16 14:44 393 查看
1.链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

/*

struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}

};*/

class Solution {

public:

    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {

        if(pListHead==NULL||k==0){

            return NULL;

        }

        ListNode *pAhead=pListHead;

        ListNode *pBehind=NULL;

        for(unsigned int i=0;i<k-1;++i){

            if(pAhead->next!=NULL){

                pAhead=pAhead->next;                

            }

            else{

                return NULL;

            }

        }

        pBehind=pListHead;

        while(pAhead->next!=NULL){

            pAhead=pAhead->next;

            pBehind=pBehind->next;

        }

       return pBehind;

    

    }

};

2.反转链表

输入一个链表,反转链表后,输出链表的所有元素。

/*

struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}

};*/

class Solution {

public:

    ListNode* ReverseList(ListNode* pHead) {
ListNode* pReversedHead=NULL;

        ListNode* pNode=pHead;

        ListNode* pPrev=NULL;

        while(pNode!=NULL){

            ListNode* pNext=pNode->next;

            if(pNext==NULL)

            pReversedHead=pNode;

         

            pNode->next=pPrev;

            pPrev=pNode;

            pNode=pNext;

            

        }

        return pReversedHead;

    }

};

3.复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

方法二:next指针关联

    创建新链表的时候,用原结点的next指针指向对应新结点,新结点的next指针指向下一个原结点,以此类推,形成之字形关联。然后,就可以先更新新链表的random指针,再解除next关联,更新next指针。这种方法不需要map来辅助,不管查找next还是random指针都是O(1)的,效率很高。

class Solution {

public:

    RandomListNode* Clone(RandomListNode* pHead)

    {

        if(pHead==NULL) return NULL;

 

        RandomListNode *newHead = new RandomListNode(pHead->label);

        RandomListNode *pHead1=NULL, *pHead2=NULL;

 

        // 上链,使新旧链表成之字形链接

        for(pHead1=pHead,pHead2=newHead;pHead1;){

            RandomListNode* tmp = pHead1->next;

            pHead1->next = pHead2;

            pHead2->next = tmp;

 

            // next

            pHead1 = tmp;

            if(tmp) pHead2 = new RandomListNode(tmp->label);

            else pHead2 = NULL;

        }

 

        // 更新新链表的random指针

        for(pHead1=pHead,pHead2=newHead;pHead1;){

            if(pHead1->random) pHead2->random = pHead1->random->next;

            else pHead2->random = NULL;

 

            pHead1 = pHead2->next;

            if(pHead1) pHead2 = pHead1->next;

            else pHead2 = NULL;

        }

 

        // 脱链,更新各链表的next指针

        for(pHead1=pHead,pHead2=newHead;pHead1;){

            pHead1->next = pHead2->next;

            if(pHead1->next) pHead2->next = pHead1->next->next;

            else pHead2->next = NULL;

 

            pHead1 = pHead1->next;

            pHead2 = pHead2->next;

        }

 

        return newHead;

    }

};

方法一:map关联

    首先遍历一遍原链表,创建新链表(赋值label和next),用map关联对应结点;再遍历一遍,更新新链表的random指针。(注意map中应有NULL ----> NULL的映射)

class Solution {

public:

    RandomListNode* Clone(RandomListNode* pHead)

    {

        if(pHead==NULL) return NULL;

 

        map<RandomListNode*,RandomListNode*> m;

        RandomListNode* pHead1 = pHead;

        RandomListNode* pHead2 = new RandomListNode(pHead1->label);

        RandomListNode* newHead = pHead2;

        m[pHead1] = pHead2;

        while(pHead1){

            if(pHead1->next) pHead2->next = new RandomListNode(pHead1->next->label);

            else pHead2->next = NULL;

            pHead1 = pHead1->next;

            pHead2 = pHead2->next;

            m[pHead1] = pHead2;

        }

 

        pHead1 = pHead;

        pHead2 = newHead;

        while(pHead1){

            pHead2->random = m[pHead1->random];

            pHead1 = pHead1->next;

            pHead2 = pHead2->next;

        }

        return newHead;

    }

};

4.两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

/*

struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}

};*/

class Solution {

public:

    ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {

        unsigned int nlength1=GetListLength(pHead1);

        unsigned int nlength2=GetListLength(pHead2);

        int nlengthDif=nlength1-nlength2;

        ListNode* pListHeadLong=pHead1;

        ListNode* pListHeadShort=pHead2;

        if(nlength2>nlength1){

            pListHeadLong=pHead2;

            pListHeadShort=pHead1;

            nlengthDif=nlength2-nlength1;

        }

        for(int i=0;i<nlengthDif;++i){

            pListHeadLong=pListHeadLong->next;

        }

        while((pListHeadLong!=NULL)&&(pListHeadShort!=NULL)&&(pListHeadLong!=pListHeadShort)){

            pListHeadLong=pListHeadLong->next;

            pListHeadShort=pListHeadShort->next;

        }

        ListNode* pFirstCommonNode=pListHeadLong;

        return pFirstCommonNode;

    }

    unsigned int GetListLength(ListNode* pHead){

        unsigned int nlength=0;

        ListNode* pNode=pHead;

        while(pNode!=NULL){

            ++nlength;

            pNode=pNode->next;

        }

        return nlength;

    }

};

5.链表中环的入口结点

一个链表中包含环,请找出该链表的环的入口结点。

/*

时间复杂度为O(n),两个指针,一个在前面,另一个紧邻着这个指针,在后面。

两个指针同时向前移动,每移动一次,前面的指针的next指向NULL。

也就是说:访问过的节点都断开,最后到达的那个节点一定是尾节点的下一个,

也就是循环的第一个。

这时候已经是第二次访问循环的第一节点了,第一次访问的时候我们已经让它指向了NULL,

所以到这结束。

*/

/*

struct ListNode {

    int val;

    struct ListNode *next;

    ListNode(int x) :

        val(x), next(NULL) {

    }

};

*/

class Solution {

public:

    ListNode* EntryNodeOfLoop(ListNode* pHead)

    {

        if (!pHead->next)

            return NULL;

        ListNode* previous = pHead;

        ListNode* front = pHead ->next;

        while (front)

        {

            previous->next = NULL;

            previous = front;

            front = front->next;

        }

        return previous;

    }

};

6.删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 

class Solution {

public:

    ListNode* deleteDuplication(ListNode* pHead)

    {

        if (pHead==NULL)

            return NULL;

        if (pHead!=NULL && pHead->next==NULL)

            return pHead;

                 

        ListNode* current;

         

        if ( pHead->next->val==pHead->val){

            current=pHead->next->next;

            while (current != NULL && current->val==pHead->val)

                current=current->next;

            return deleteDuplication(current);                     

        }

         

        else {

            current=pHead->next;

            pHead->next=deleteDuplication(current);

            return pHead;

        }    

    }

};

7.访问单个节点的删除

实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。

给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true

/*

struct ListNode {

    int val;

    struct ListNode *next;

    ListNode(int x) : val(x), next(NULL) {}

};*/

class Remove {

public:

    bool removeNode(ListNode* pNode) {

        if(pNode == NULL || (pNode != NULL &&  pNode->next == NULL )) return false;

         

        pNode->val = pNode->next->val;

        pNode->next = pNode->next->next;

        delete pNode->next;

        return true;

    }

};

8.链表分割

编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

给定一个链表的头指针 ListNode* pHead,请返回重新排列后的链表的头指针。注意:分割以后保持原来的数据顺序不变。

/*

struct ListNode {

    int val;

    struct ListNode *next;

    ListNode(int x) : val(x), next(NULL) {}

};*/

class Partition {

public:

    ListNode* partition(ListNode* pHead, int x) {

        // write code here

        ListNode* beforeStart=NULL;

        ListNode* beforeEnd=NULL;

        ListNode* afterstart=NULL,*afterEnd=NULL;

        ListNode* headval;

        while(pHead)

        {

            headval=pHead->next;

            if(pHead->val<x)

            {

                if(beforeEnd==NULL)

                    beforeEnd=beforeStart=pHead;

                else

                {

                    beforeEnd->next=pHead;

                    beforeEnd=pHead;

                }

            }

            else

            {

                if(afterstart==NULL)

                {

                    afterstart=afterEnd=pHead;

                }

                else

                {

                    afterEnd->next=pHead;

                    afterEnd=pHead;

                }

            }

            pHead=headval;

        }

        if(afterEnd)

            afterEnd->next=NULL;

        if(beforeEnd!=NULL)

            beforeEnd->next=afterstart;

        else

            beforeStart=afterstart;

        return beforeStart;

    }

};

9.链式A+B

有两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表的首部。编写函数对这两个整数求和,并用链表形式返回结果。

给定两个链表ListNode* A,ListNode* B,请返回A+B的结果(ListNode*)。

测试样例:

{1,2,3},{3,2,1}

返回:{4,4,4}

本题的思路很简单,按照小学数学中学习的加法原理从末尾到首位,对每一位对齐相加即可。技巧在于如何处理不同长度的数字,以及进位和最高位的判断。这里对于不同长度的数字,我们通过将较短的数字补0来保证每一位都能相加。

/*

struct ListNode {

    int val;

    struct ListNode *next;

    ListNode(int x) : val(x), next(NULL) {}

};*/

class Plus {

public:

    ListNode* plusAB(ListNode* a, ListNode* b) {

        // 头结点

        ListNode *head = new ListNode(-1);

        ListNode *p = head;

        ListNode *node = nullptr;

        int c = 0,sum,val1,val2;

        ListNode *pa = a,*pb = b;

        //加法

        while(pa != nullptr || pb != nullptr || c != 0){

            val1 = (pa == nullptr ? 0 : pa->val);

            val2 = (pb == nullptr ? 0 : pb->val);

            sum = val1 + val2 + c;

            // 进位

            c = sum / 10;

            node = new ListNode(sum % 10);

 

            //尾插法

            p->next = node;

            p = node;

            pa = (pa == nullptr ? nullptr : pa->next);

            pb = (pb == nullptr ? nullptr : pb->next);

        }//while

        return head->next;

    }

};

10.回文链表

请编写一个函数,检查链表是否为回文。

给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。

测试样例:

{1,2,3,2,1}

返回:true

{1,2,3,2,3}

思路:利用快慢指针,找到中间节点;将慢指针节点的值压入栈,到达中间节点后,依次出栈与后续节点的值比较。特别注意长度奇偶数。

/*

struct ListNode {

    int val;

    struct ListNode *next;

    ListNode(int x) : val(x), next(NULL) {}

};*/

class Palindrome {

public:

    bool isPalindrome(ListNode* pHead) {

        // write code here

        if(pHead == NULL)

            return true;

        stack<int> ss;

        ListNode* p = pHead;

        ListNode* q = pHead;

        ss.push(p->val);

        while(q->next != NULL && q->next->next != NULL)

            {

            p = p->next;

           ss.push(p->val);

            q = q->next->next;

        }

        if(q->next == NULL)                                                    //长度为奇数

            ss.pop();

        p = p->next;

        while(!ss.empty())

            {

            if(ss.top() != p->val)

                break;

            p = p->next;

            ss.pop();

        }

        if(ss.empty())

            return true;

        else

            return false;

    }

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: