链表问题

单链表与双链表

单链表的节点结构
Class Node{

V value;

Node next;

}
由以上结构的节点依次连接起来所形成的链叫单链表结构。
双链表的节点结构
Class Node{

V value;

Node next;

Node last;

}
由以上结构的节点依次连接起来所形成的链叫双链表结构。
单链表和双链表结构只需要给定一个头部节点head,就可以找到剩下的所有的节点。

解答链表相关问题时的技巧:

使用额外数据结构记录(哈希表等);

使用快慢指针。

反转单向和双向链表

【题目】 分别实现反转单向链表和反转双向链表的函数

【要求】 如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度要求为 O(1)

  //问题1:反转输出链表
    //使用栈,时间复杂度为O(N),空间复杂度为O(N)
    static void reverseList(Node* head){
        Node*p = head;
        stack<Node> myStack;
        for( ; p != NULL; p = p->next){
            myStack.push(*p);
        }
        while(!myStack.empty()){
            cout << myStack.top().data<< " ";
            myStack.pop();
        }
 
    }
 
    //改变链表的结构,让第i个节点的next指向第i - 1个节点。时间复杂度为O(N),空间复杂度为O(1)
    static Node* reverseList_1(Node* head){
        Node* pre = NULL;
        Node* next = NULL;
        while(head != NULL){
            next = head->next;
            head->next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

打印两个有序链表的公共部分

【题目】 给定两个有序链表的头指针head1和head2,打印两个链表的公共部分。

【要求】 如果两个链表的长度之和为N,时间复杂度要求为O(N),额外空间复 杂度要求为O(1)

  static void printfCommentPart(Node* head_1,Node* head_2){
        while(head_1 != NULL && head_2 != NULL){
            if(head_1->data == head_2->data){
                cout << head_1->data << " ";
                head_1 = head_1->next;
                head_2 = head_2->next;
            }else{
                head_1->data > head_2->data ? head_2 = head_2->next : head_1 = head_1->next;
            }
        }
    }

判断一个链表是否为回文结构

【题目】给定一个单链表的头节点head,请判断该链表是否为回文结构。

【例子】1->2->1,返回true; 1->2->2->1,返回true;15->6->15,返回true; 1->2->3,返回false。

【要求】如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。

 //将链表全部压入栈中,依次弹出与链表元素比对
    //时间复杂度为O(N),空间复杂度为O(N)
    static bool isPalindromeList(Node* head){
        Node* p = head;
        stack<Node> myStack;
        while(p != NULL){
            myStack.push(*p);
            p = p->next;
        }
        for(p = head; p != NULL&&p->data == myStack.top().data; p = p->next,myStack.pop());
        if(p == NULL)
            return true;
        return false;
    }
    //将链表的后半部分压入栈中(快慢指针:快指针一次经过2个节点,慢指针一次经过1个节点)
    //时间复杂度为O(N),空间复杂度为O(N/2)
    static bool isPalindromeList_1(Node* head){
        if(head == NULL || head->next == NULL)
            return true;
        Node* f = head;
        Node* s = head;
        while(f->next != NULL && f->next->next != NULL){
            s = s->next;
            f = f->next->next;
 
        }
        stack<Node> myStack;
        if(f->next != NULL){
            s = s->next;
        }
        for(f = s ; f != NULL; f = f->next){
            myStack.push(*f);
        }
        for( ;!myStack.empty() && head->data == myStack.top().data;head = head->next,myStack.pop());
        if(head == s->next)
            return true;
        return false;
    }
    //将链表一分为二,倒转后一个链表
    //时间复杂度为O(N),空间复杂度为O(1)
    //head:链表首节点;head_1:分离后前一个链表的首节点;Head_2:分离后右边链表的首节点;temp_1:前一个链表的尾节点;temp_2:到转后右边链表的首节点
    static bool isPalindromeList_2(Node* head){
        if(head == NULL || head->next == NULL)
            return true;
        Node* f = head;
        Node* s = head;
        bool res = false;
        //分离
        while(f->next != NULL && f->next->next != NULL){
            s = s->next;
            f = f->next->next;
        }
        Node* head_1 = head;
        Node* head_2 = s->next;//第二个链表
        Node* temp_1 = s;//第一个链表的最后一个节点
        s->next = NULL;
 
        //倒转右边的链表
        s = NULL;
        while( head_2!= NULL){
            f = head_2->next;
            head_2->next = s;
            s = head_2;
            head_2 = f;
        }
        Node* temp_2 = s;
        for(head_2 = s;head_1 != NULL && head_2 != NULL && head_1->data == head_2->data;head_1 = head_1->next,head_2 = head_2->next);//{
        if(head_2 == NULL)
            res = true;
        s == NULL;
        head_2 = temp_2;
        while(head_2 != NULL){
 
 
            f = head_2->next;
            head_2->next = s;
            s = head_2;
            head_2 = f;
        }
       temp_1->next = s;
        return res;
    }

将单向链表按某值划分成左边小、中间相等、右边大的形式

【题目】给定一个单链表的头节点head,节点的值类型是整型,再给定一个整 数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于pivot的 节点,中间部分都是值等于pivot的节点,右部分都是值大于pivot的节点。
【进阶】在实现原问题功能的基础上增加如下的要求

【要求】调整后所有小于pivot的节点之间的相对顺序和调整前一样

【要求】调整后所有等于pivot的节点之间的相对顺序和调整前一样

【要求】调整后所有大于pivot的节点之间的相对顺序和调整前一样

【要求】时间复杂度请达到O(N),额外空间复杂度请达到O(1)。

 //用额外空间存储链表中的数据,然后使用快速排序中的partition方法对额外空间排序
    //按照额外空间中的存储顺序修改链表中的值
    static void partition (vector<int>& v,int l,int r){
        if(l >= r)
            return;
        int num = v[rand() % (r - l + 1)];
        int less = l - 1;
        int more = r + 1;
        for(int i = l; i < r; ){
            if(v[i] < num){
                swap(v[i++],v[++less]);
            }else if(v[i] > num){
                swap(v[i],v[--more]);
            }else{
                i++;
            }
        }
        partition(v,l,less);
        partition(v,more,r);
    }
 
    static Node* smallEqualBigger(Node* head){
        vector<int> v;
        Node* p = head;
        for( ; p != NULL; p = p->next){
            v.push_back(p->data);
        }
        partition(v,0,v.size());
        int i = 0;
//        for( ; i < v.size();i++){
//            cout << v[i] << " ";
//        }
//        cout << endl;
        for(p = head; p != NULL && i < v.size(); p = p->next,i++){
 
            p->data = v[i];
        }
        return head;
    }
 
 
  
//直接在链表上进行划分
    static Node* smallEqualBigger_1(Node* head,int pivot){
        Node* sH = NULL;
        Node* sT = NULL;
        Node* lH = NULL;
        Node* lT = NULL;
        Node* eH = NULL;
        Node* eT = NULL;
        for(; head != NULL; head = head->next){
            if(head->data < pivot){
                if(sH == NULL){
                    sH = head;
                    sT = head;
                }else{
                    sT->next = head;
                    sT = head;
                }
            }else if(head->data > pivot){
                if(lH == NULL){
                    lH = head;
                    lT = head;
                }else{
                    lT->next = head;
                    lT = head;
                }
            }
            else{
                if(eH == NULL){
                    eH = head;
                    eT = head;
                }else{
                    eT->next = head;
                    eT = head;
                }
            }
          //  cout << head->data << endl;
        }
        if(sT != NULL)
            sT->next = eH;
        if(eT != NULL)
            eT->next = lH;
        return sH != NULL ? sH : eH != NULL ? eH : lH;
    }

复制含有随机指针节点的链表

【题目】一种特殊的单链表节点类描述如下
class Node {

int value;

Node next;

Node rand;

Node(int val){ value = val; }

}

rand指针是单链表节点结构中新增的指针,rand可能指向链表中的任意一个节 点,也可能指向null。给定一个由Node节点类型组成的无环单链表的头节点 head,请实现一个函数完成这个链表的复制,并返回复制的新链表的头节点。
【要求】时间复杂度O(N),额外空间复杂度O(1)

   //不考虑空间复杂度,使用map来存储新的链表节点
    static NodeWithRand* copyListWithRand(NodeWithRand* head){
        if(head == NULL){
            return NULL;
        }
        map<NodeWithRand*,NodeWithRand*> m;
        map<NodeWithRand*,NodeWithRand*>::iterator iter;
        NodeWithRand* p = head;
        for( ; p != NULL; p = p->next){
            m.insert(pair<NodeWithRand*,NodeWithRand*>(p,new NodeWithRand(p->data)));
        }
        for(p = head; p!= NULL; p = p->next){
            iter = m.find(p);
            iter->second->next = p->next == NULL ? NULL :m.find(p->next)->second;
            iter->second->rand = p->rand == NULL ? NULL : m.find(p->rand)->second;
        }
 
//        for(p = m[head]; p != NULL; p = p->next){
//            cout << p->data << " ";
//            cout << p->rand << " ";
//            if(p->rand != NULL)
//                cout << " randData:" << p->rand->data << endl;
//        }
        return m[head];
    }
 
    //空间复杂度为O(1),创建新节点时将新节点加到老节点的后面,其余不变
    static NodeWithRand* copyListWithRand_1(NodeWithRand* head){
        if(head == NULL)
            return NULL;
        NodeWithRand* p = head;
        NodeWithRand* copyHead = NULL;
        for( p = head; p != NULL; p = p->next->next){
            NodeWithRand* temp = new NodeWithRand(p->data);
            temp->next = p->next;
            p->next = temp;
        }
        for(p = head; p != NULL && p->next != NULL; p = p->next->next){
            NodeWithRand* temp = p->next;
            temp->rand = p->rand == NULL ? NULL :p->rand->next;
        }
        copyHead = head->next;
        for(p = head; p != NULL && p->next != NULL; p = p->next){
            NodeWithRand* temp = p->next;
            p->next = p->next->next != NULL ? p->next->next : NULL;
            temp->next = temp->next != NULL ? temp->next->next : NULL;
 
        }
        return copyHead;
    }

两个单链表相交的一系列问题

【题目】给定两个可能有环也可能无环的单链表,头节点head1和head2。请实 现一个函数,如果两个链表相交,请返回相交的 第一个节点。如果不相交,返 回null

【要求】如果两个链表长度之和为N,时间复杂度请达到O(N),额外空间复杂度 请达到O(1)。

//问题6:两个单链表相交的问题
    //判断链表是否有环,有则返回环节点,否则返回NULL
    static Node* getLoopNode(Node* head){
        if(head == NULL || head->next == NULL)
            return NULL;
        Node* f = head->next->next;
        Node* s = head->next;
        //cout << f->data << endl;
        int i = 0;
        //cout << f->data << " " << s->data << " " << i <<endl;
        for( ;f->next != NULL && f->next->next != NULL && s != f;f = f->next->next,s = s->next,i++);
        if(s == NULL || f == NULL){
            return NULL;
        }
        f = head;
        for( ; f != s;f = f->next,s = s->next);
        //cout << s->data << endl;
        return s;
    }
    //判断两个链表都没有环的情况
    static Node* getNoLoop(Node* head1,Node* head2){
        if(head1 == NULL ||  head2 == NULL)
            return NULL;
        int n = 0;
        for( ; head1 != NULL; head1 = head1->next)
            n++;
        for( ; head2 != NULL; head2 = head2->next)
            n--;
        Node* longList = n >= 0 ? head1 : head2;
        Node* shortList = n >= 0 ? head2 : head1;
        for( ; n >= 0; n--,longList = longList->next);
        for( ; longList != shortList && longList != NULL && shortList != NULL;longList = longList->next,shortList = shortList->next);
        if(longList == shortList)
            return longList;
        return NULL;
 
    }
    //判断两个链表各自有自己的环的情况
    static Node* getBothLoop(Node* head1,Node* head2,Node* loop1,Node* loop2){
        if(loop1 == loop2){
            int n = 0;
            for( ; head1 != NULL; head1 = head1->next)
                n++;
            for( ; head2 != NULL; head2 = head2->next)
                n--;
            Node* longList = n >= 0 ? head1 : head2;
            Node* shortList = n >= 0 ? head2 : head1;
            for( ; n >= 0; n--,longList = longList->next);
            for( ; longList != shortList;longList = longList->next,shortList = shortList->next);
            return longList;
        }else{
            Node* p = loop1->next;
            for( ; p != loop1 && p != loop2;p = p->next);
            if(p == loop2)
                return p;
            return NULL;
        }
    }
    //判断两个链表是否相交,相交返回交点,否则返回NULL
    static Node*  getIntersectNode(Node* head1,Node* head2){
        if(head1 == NULL || head2 == NULL)
            return NULL;
        Node* loop1 = getLoopNode(head1);
        Node* loop2 = getLoopNode(head2);
        //cout << loop1->data << " " << loop2->data << endl;
        if(loop1 == NULL && loop2 == NULL){
            return getNoLoop(head1,head2);
        }else if(loop1 != NULL && loop2 != NULL){
            return getBothLoop(head1,head2,loop1,loop2);
        }
        return NULL;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值