Leetcode中几道链表题

继数组之后,Linklist算是第二基础的数据结构吧,写代码的时候思路清晰就好,不熟悉的现在草稿纸上验算好。


题目一:Sort List

Sort a linked list in O(nlogn) time using constant space complexity.

思路:这道题算是经典题了,Mergesort应该算是比较好实现的O(nlogn) 算法,该算法两部分比较重要:split和merge,掌握链表之间的merge思路,也就没啥了。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *sortList(ListNode *head) {
        if(head==NULL || head->next==NULL) return head;
        
        //split two part
        int len=0;
        for(ListNode *node=head; node; node=node->next)
            len++;
        ListNode *first, *second, *tail;
        first=tail=head;
        for(int n=0; n<len/2-1; n++)
            tail=tail->next;
        second=tail->next;
        tail->next=NULL;
        
        first=sortList(first);
        second=sortList(second);
        
        //merge two sorted list
        tail=NULL;
        ListNode *p=NULL;
        while(first && second){
            if(first->val <= second->val){
                p=first;
                first=first->next;
            }
            else{
                p=second;
                second=second->next;
            }
            if(tail==NULL){
                tail=head=p;
            }
            else{
                tail->next=p;
                tail=tail->next;
            }
        }
        if(first) tail->next=first;
        if(second) tail->next=second;
        
        return head;
    }
};

题目二: Insertion Sort List

Sort a linked list using insertion sort.

思路:插入排序的基本思想就是将需要排序的节点一个个插入到前面已经排好序的list中去。两层循环。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *insertionSortList(ListNode *head) {
        if(head==NULL || head->next==NULL) return head;
        ListNode *dummy=new ListNode(0); //引入dummy node
        dummy->next=head;
        head=dummy;
        
        ListNode *p1, *p2;
        p1=head->next;
        while(p1&&p1->next){
            ListNode *p=p1->next;  、、
            for(p2=head; p2->next!=p1->next; p2=p2->next){  //这里的终止条件是p1->next,不能是p
                if(p->val<p2->next->val){
                    p1->next=p->next;
                    p->next=p2->next;
                    p2->next=p;
                    break; //又忘记这个,怎么办。。。                           
                }
            }
            if(p2->next==p1->next) p1=p1->next; //总是忘记这个,该怎么办。。
        }
        return head->next;
    }
};

题目三: Reorder List

Given a singly linked list L: L0->L1->...->Ln-1->Ln, reorder it to: L0->Ln->L1->Ln-1->L2->Ln-2->..., you must do this in-place without altering the nodes' value.

思路:我解题的思路是先将list分成两部分,将后一部分reverse,然后再将list合并掉。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverse(ListNode *head){   //reverse实现,将头变成尾部,尾部变成头部
        if(head==NULL || head->next==NULL) return head;
        
        ListNode *p1, *p2, *p3;
        p1=head;
        p2=p1->next;
        while(p2){
            p3=p2->next;
            p2->next=p1;
            p1=p2;
            p2=p3;
        }
        head->next=NULL;  //将新链表尾部置空!
        return p1;
    }
    
    void reorderList(ListNode *head) {   
        if(head==NULL || head->next==NULL) return;
        ListNode *p1, *p2;
        p1=head;
        p2=head->next;   //p2要先走一步!
        while(p2&&p2->next){   //找到链表中间位置的前一个位置
            p1=p1->next;
            p2=p2->next->next;
        }
        p2=p1->next;
        p2=reverse(p2); //将第二条链表反转
        p1->next=NULL;
        p1=head;
        while(p2){      //merge掉两个链表
            ListNode *p3=p2->next;
            p2->next=p1->next;
            p1->next=p2;
            p2=p3;
            p1=p1->next->next;
        }
    }
};

题目三: Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.

思路:这道题不能不能通过常规的遍历思路来解答。网上介绍的思路是想将该List原地拷贝一份,然后再将子链表从母链表中分离出来

/**
 * Definition for singly-linked list with a random pointer.
 * struct RandomListNode {
 *     int label;
 *     RandomListNode *next, *random;
 *     RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
 * };
 */
class Solution {
public:
    RandomListNode *copyRandomList(RandomListNode *head) {
        if(head==NULL) return NULL;
        //copy each node in the original list
        RandomListNode *hcopy, *p1, *p2, *p;
        p1=head;
        while(p1){
            p=new RandomListNode(p1->label);
            p2=p1->next;
            p1->next=p;
            p->next=p2;
            p1=p2;
        }
        // copy the radom pointer in place
        p1=head;
        while(p1){
            p2=p1->next;
            if(p1->random){
                p=p1->random;
                p2->random=p->next;
            }
            p1=p2->next;
        }
        // split the copy list from the original one
        p1=head;
        p2=hcopy=p1->next;
        while(p2->next){
            p1->next=p2->next;
            p1=p1->next;
            p2->next=p1->next;
            p2=p2->next;
        }
        p1->next=NULL;  //最后的分离节点置空!
        
        return hcopy;
    }
};

下面来几道dummy node发挥奇效的题目!


题目四:Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head. For example, given 1->2->3->4, you should return the list as 2->1->4->3.  Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.

思路:添加dummy nodes

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *swapPairs(ListNode *head) {
        if(head==NULL || head->next==NULL) return head;
        
        ListNode *dummy=new ListNode(0);
        dummy->next=head;
        head=dummy;
        
        ListNode *p1, *p2, *p3;
        p1=head;
        p2=p1->next;
   
        while(p2&&p2->next){
            p3=p2->next;
            p2->next=p3->next;
            p3->next=p2;
            p1->next=p3;
            p1=p2;
            p2=p1->next;
            
        }
        return head->next;
    }
};

题目五: Reverse Nodes in K-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. You may not alter the values in the nodes, only nodes itself may be changed. For example, Given the linked list: 1->2->3->4->5, For k=2, you should return 2->1->4->3->5. For k=3, you should return 3->2->1->4->5.

思路:每k个节点一起处理。先反转这k个节点,在调整首尾指针的值。  

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *reverseKGroup(ListNode *head, int k) {
        if(head==NULL || head->next==NULL) return head;
    
        ListNode *dummy=new ListNode(0);  //神奇的dummy node~
        dummy->next=head;
        head=dummy;
        
        ListNode *p1, *p2, *p3, *p, *cur;
        cur=head;
        while(cur->next){
            p=cur->next;
            int cnt=0;
            while(cnt<k && p){ p=p->next; cnt++; }
            if(cnt<k) break;
            
            p1=cur->next;  //有效位第一位
            p2=p1->next;
            p1->next=p;
            while(p2!=p){
                p3=p2->next;
                p2->next=p1;
                p1=p2;
                p2=p3;
            }
            p2=cur->next;  //保存cur下一个位置
            cur->next=p1;
            cur=p2;
        }
        return head->next;
    }
};

题目六: Partition List

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the nodes in each of the two partitions. For example, given 1->4->3->2->5->2 and x=3, return 1->2->2->4->3->5.

思路:将原list按照小于等于target和大于target分成两个list,然后在合并。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *partition(ListNode *head, int x) {
        if(head==NULL) return NULL;
        ListNode *l1, *l2, *l3,*p, *p1, *p2;
        p1=p2=l3=l1=l2=NULL;
        p=head;
        while(p){
            if(p->val<x){
                if(l1==NULL){ l1=p1=p; }
                else{ p1->next=p; p1=p1->next; }
                p=p->next;
            }
            else{
                if(l2==NULL){ l2=p2=p; }
                else{ p2->next=p; p2=p2->next; }
                p=p->next;
            }
        }
        if(l1){l3=l1; p1->next=l2; }
        else{ l3=l2;}
        if(p2) p2->next=NULL;
        
        return l3;
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值