leetcode--链表

#基本操作
链表基本结构:

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

新建节点:
ListNode new_list(0);p=(ListNode *)malloc(sizeof(ListNode *));
头插法建立链表:

ListNode *head=NULL;
p=(ListNode *)malloc(sizeof(ListNode *));
p->val=data_int;
p->next=head;
head=p;

尾插法建立链表:
尾插法需要多消耗一个tmp指针,且要判断插入的是不是第一个节点。

ListNode *head=NULL;
ListNode *tmp=NULL;
p=(ListNode *)malloc(sizeof(ListNode *))
if(head==NULL){
	head=p;
}
else{
	e->next=p;
}
p->val=data_int;
e=p;
/*最后加上if(head!=NULL) e->next=NULL;*/

带头节点的尾插法:
带头节点可以省去每次判断是否为头节点的操作。

ListNode false_head(0);
ListNode *false_head_p=&false_head;

p=(ListNode *)malloc(sizeof(ListNode *));
p->val=data_int;
false_head_p->next=p;
false_head_p=p;
//最后返回时可以拿false_head的地址

#leetcode题目
##160:Intersection of Two Linked Lists
###题意:
找出两个链表相交的第一个节点

  1. 两个链表没有相交则return NULL
  2. 必须保持两个链表原有的结构
  3. 可以假定两个链表没有环
  4. 时间复杂度为O(n)空间复杂度为O(1)
###解体思路: 先将两个链表对齐,再同时遍历两个链表找出第一个相同的节点。 ###代码: ```c++ int get_list_len(ListNode *head){ int i=0; while(head){ head=head->next; i++; } return i; } ListNode* getIntersectionNode(ListNode *headA,ListNode *headB){ int n1=get_list_len(headA); int n2=get_list_len(headB); int len=0; if(n1>n2){ ListNode *tmp=headA; headA=headB; headB=tmp; len=n1-n2; } else{ len=n2-n1; } if(headB==NULL) return NULL; while(len>0){ headB=headB->next; len--; } while(headA&&headB){ if(headA==headB){ return headA; } headA=headA->next; headB=headB->next; } return NULL; } ``` ##206:Reverse Linked List ###题意: 翻转链表 ###解题思路: 利用头插法建立新的链表 ###代码: ```c++ ListNode* reverseList(ListNode *head){ ListNode *new_head=NULL; ListNode *next=NULL; while(head){ next=head->next; head->next=new_head; new_head=head; head=next; } return new_head; }; ``` ##92:Reverse Linked List II ###题意: 翻转链表中m到n中的节点。 例如: 给定 1->2->3->4->5->NULL, m = 2 and n = 4, 返回1->4->3->2->5->NULL. ###解题思路: 分段执行: 1 前m-1个节点(0到m-2)不变,head=head->next,记录m-2 2 中间m-1个(节点号m-2)到n个(节点号n-1)处用头插法翻转链表(共n-m+1个节点),同时记录节点号m-1和节点号n-1,让m-2节点号指向n-1节点号,m-1节点号指向n节点号。 3后面的链表不变。 4分情况讨论 若是从第一个节点开始反转则返回的头节点是n-1号节点,若不是从第一个节点开始反转则返回原头节点. 注意: 1 使用ListNode->next时要先判断ListNode是否为非空。 ###代码: ```c++ ListNode* reverseBetween(ListNode* head,int m,int n){ int reverse_len=n-m+1; ListNode *prehead=NULL;//记录第m-2号节点 ListNode *new_reverse_tail=NULL;//记录第m-1号节点 ListNode *next=NULL; ListNode *new_reverse_head=NULL; //记录第n-1号节点 ListNode *result=head; while(head&&m>1){ prehead=head; head=head->next; m--; } new_reverse_tail=head; while(head&&reverse_len>0){ next=head->next; head->next=new_reverse_head; new_reverse_head=head; head=next; reverse_len--; } if(new_reverse_tail!=NULL) new_reverse_tail->next=head; if(prehead){ prehead->next=new_reverse_head; } else { result=new_reverse_head; } return result; } ``` ##86:Partition List ###题意: 给定一个链表和一个值x,将链表划分,使得比x小的值排在比x大或者等于x的值的前面,且保证原来的相对位置不变。 ###解题思路: 新建两个节点,用尾插法建立链表,再将两个链表相连,用带头节点尾插法可以使建立链表不用做判断是否为第一个节点的工作。 注意:最后的节点要加上NULL,否则会报超时错误。 ###代码 ```c++ ListNode* partition(ListNode* head, int x) { ListNode less_x(0); ListNode more_x(0); ListNode *less_x_p=&less_x; ListNode *more_x_p=&more_x;
while(head){
    if(head->val<x){
        less_x_p->next=head;
        less_x_p=head;
    }
    else{
        more_x_p->next=head;
        more_x_p=head;
    }
    head=head->next;
}
less_x_p->next=more_x.next;
more_x_p->next=NULL;
return less_x.next;

}

##138:Copy List with Random Pointer
###题意:
深度复制一个带有附加随机指针的链表,附加的随机指针会指向在链表里任意的一个节点或者NULL,结构定义如下:
```c++
/**
 * 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) {}
 * };
 */

###解题思路:
利用map和vector结构,map记录原RandomListNode和原来的位置关系,让map存储原链表及它的位置信息,vector储存新复制的链表。
用map:#include <map>
用vector:#include <vector>
注意:最后要加入一个空节点。用到指针->next 或a[i+1]时要考虑边界情况。
###代码:

RandomListNode *copyRandomList(RandomListNode *head) {
    RandomListNode *ptr=head;
    std::map<RandomListNode *,int> random_node_map;
    vector<RandomListNode *> new_node_vector;
    int i=0;
    while(ptr){
        random_node_map[ptr]=i;
        i++;
        new_node_vector.push_back(new RandomListNode(ptr->label));
        ptr=ptr->next;
    }
    new_node_vector.push_back(0);
    ptr=head;
    i=0;
    while(ptr){
        if(ptr->random){
            int id=random_node_map[ptr->random];
            new_node_vector[i]->random= new_node_vector[id];
        }
//        new_node_vector[i]->next=new_node_vector[random_node_map[ptr->random]];
        new_node_vector[i]->next=new_node_vector[i+1];
        ptr=ptr->next;
        i++;
    }
    return new_node_vector[0];
}

23:Merge k Sorted Lists

题意:

合并K个已排好序的链表为1个有序的链表

解题思路:

方法1: 自定义链表的比较函数,用SLT中的sort函数排序,全部压入一个vector中,用sort排序,再链接起来,此时时间复杂度为O(KNlogKN)
方法2:用分治算法,合并两个有序链表的时间复杂度是O(m+n)。每次两两合并:
第一次合并K/2次,每个是2N个数 每次的复杂度都为O(KN)
第二次合并K/4次,每次是4N个数

时间复杂度是O(KNlogK)

代码

方法一:

ListNode* mergeKLists(std::vector<ListNode*> &lists){
    std::vector<ListNode*> node_vec;
    for (int i=0;i<lists.size();i++){
        ListNode *head=lists[i];
        while(head){
            node_vec.push_back(head);
            head=head->next;
        }
    }
    if(node_vec.size()==0){
        return NULL;
    }
    std::sort(node_vec.begin(),node_vec.end(),cmp);
    for (int i=1;i<node_vec.size();i++){
        node_vec[i-1]->next=node_vec[i];
    }
    node_vec[node_vec.size()-1]->next=NULL;
    return node_vec[0];
}

方法二:

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    ListNode tmp_head(0);//建一个虚拟的头节点
    ListNode *head=&tmp_head;
    while(l1&&l2){
        if(l1->val<l2->val){
            head->next=l1;
            head=l1;
            l1=l1->next;
        }
        else{
            head->next=l2;
            head=l2;
            l2=l2->next;
        }
    }
    if(l1){
        head->next=l1;
    }
    if(l2){
        head->next=l2;
    }
    return tmp_head.next;
}

ListNode* mergeKlists(std::vector<ListNode*> &lists){
    if(lists.size()==0){
        return NULL;
    }
    if(lists.size()==1){
        return lists[0];
    }
    if(lists.size()==2){
        return mergeTwoLists(lists[0],lists[1]);
    }
    int mid=lists.size()/2;
    std::vector<ListNode*> sub1_lists;
    std::vector<ListNode*> sub2_lists;
    for (int i=0;i<mid;i++){
        sub1_lists.push_back(lists[i]);
    }
    for (int i=mid;i<lists.size();i++){
        sub2_lists.push_back(lists[i]);
    }
    ListNode *l1=mergeKlists(sub1_lists);
    ListNode *l2=mergeKlists(sub2_lists);
    return mergeTwoLists(l1,l2);
}

##19. Remove Nth Node From End of List
###代码:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* result = head;
        ListNode* prehead = head;
        ListNode* delete_node = NULL;
        
        while(head && n > 0){
            head = head->next;
            n--;
        }
        
        if(head == NULL){
            delete_node = result;
            result = result->next;
            delete delete_node;
            return result;
        }

        while(head->next){
            head = head->next;
            prehead = prehead->next;
        }
        delete_node = prehead->next;
        prehead->next = prehead->next->next;
        delete delete_node;
        return result;
    }
};

###方法二(二级指针):
凡是要用到节点的前驱的都可以用二级指针实现对节点的管理,从而不用知道节点的前驱。
对于二级指针的理解可以参考:https://coolshell.cn/articles/8990.html

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode** del = &head;
        ListNode* ptr = head;
        
        while(ptr && n > 0){
            ptr = ptr->next;
            n--;
        }
        
        while(ptr){
            ptr = ptr->next;
            del = &((*del)->next);
        }
        
        ListNode* tmp = *del;
        *del = (*del)->next;
        delete tmp;
        return head;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值