链表

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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值