• A 第一课 链表


    脑筋急转弯:

    答案一:

    经理生成个随机数num,a员工加上随机数再告诉员工b,依次类推,最会得到个值val ,

    就可以求出平均值:

    avg = (val -num)/3   

    答案二:

    设计个程序,让每个员工都输入自己的工资,然后求和平均即可。

    链表概述:

    预备知识:链表基础:

    基础(c语言版

     1 #include <stdio.h>
     2 struct ListNode {
     3     int val;
     4     struct ListNode* next;
     5 };
     6 
     7 int main() {
     8     struct ListNode node1;
     9     struct ListNode node2;
    10     struct ListNode node3;
    11     struct ListNode node4;
    12     struct ListNode node5;
    13 
    14     node1.val = 10;
    15     node2.val = 20;
    16     node3.val = 30;
    17     node4.val = 40;
    18     node5.val = 50;
    19 
    20     node1.next = &node2;
    21     node2.next = &node3;
    22     node3.next = &node4;
    23     node4.next = &node5;
    24     node5.next = NULL;
    25 
    26     struct ListNode *pCurrent = &node1;
    27     while (pCurrent != NULL) {
    28         printf("%d 
    ", pCurrent->val);
    29         pCurrent = pCurrent->next;
    30     }
    31     return 0;
    32 }
    33 /*
    34 10
    35 20
    36 30
    37 40
    38 50
    39 
    40 
    41 */

     

    基础(c++版)

     1 #include <stdio.h>
     2 struct ListNode {
     3     int val;
     4     struct ListNode * next;
     5 };
     6 
     7 int main(){
     8     
     9     ListNode node1;
    10     ListNode node2;
    11     ListNode node3;
    12     ListNode node4;
    13     ListNode node5;
    14     
    15     node1.val = 10;
    16     node2.val = 20;
    17     node3.val = 30;
    18     node4.val = 40;
    19     node5.val = 50;
    20     
    21     node1.next = &node2;
    22     node2.next = &node3;
    23     node3.next = &node4;
    24     node4.next = &node5;
    25     node5.next = NULL;
    26     
    27     ListNode * pCurrent = &node1;
    28     while(pCurrent != NULL){
    29         printf("%d 
    ",pCurrent->val);
    30         pCurrent = pCurrent->next ;
    31     }
    32     return 0;
    33 }

    二者的主要区别是:c++ 可以没有 struct !

     1 #include <iostream>
     2 using namespace std;
     3 
     4 //链表相关的基础
     5 struct ListNode {
     6     int val;
     7     struct ListNode * next;
     8 };
     9 
    10 struct ListNode * ListInit(){
    11     struct ListNode * head =(struct ListNode *)malloc(sizeof(struct ListNode));
    12     head->val = 0;
    13     head->next = NULL;
    14 
    15     return head;
    16 }
    17 void printList(struct ListNode * head){
    18     while(head != NULL){
    19         printf("Val: %d
    ",head->val,head->next);
    20         head = head->next;
    21     }
    22 }
    23 void addOneNode(struct ListNode * head,int val){
    24     struct ListNode * newNode  =(struct ListNode *)malloc(sizeof(struct ListNode));
    25     newNode->val = val;
    26     newNode->next = NULL;
    27 
    28     //遍历链表到 尾部
    29     struct ListNode * temp = head;
    30     while(temp->next !=NULL){
    31         temp = temp->next;
    32     }
    33     temp->next = newNode;
    34 }
    35 
    36 int main(){
    37 
    38     struct ListNode * head = ListInit();  //head存数据(默认存的值为0)
    39     head->val = 1; //这里将默认的head.val =0 变为1
    40     for(int i =2;i<10;++i){
    41         addOneNode(head,i);
    42     }
    43     printList(head);
    44     return 0;
    45 }
    链表基础回顾!!!

    例1-a:链表逆序-a  (leetcode 编号 206)

     

    注:不允许申请额外的空间。

    自己的代码:(缺点是:当head 为空的时候不能通过, 而且最后一个还要在循环外另外写一下!!! 优点是:它没有在循环中重复声明pNext变量)

     1 #include <iostream>
     2 using namespace std;
     3 
     4 //链表相关的基础
     5 struct ListNode {
     6     int val;
     7     struct ListNode * next;
     8 };
     9 
    10 struct ListNode * ListInit(){
    11     struct ListNode * head =(struct ListNode *)malloc(sizeof(struct ListNode));
    12     head->val = 0;
    13     head->next = NULL;
    14 
    15     return head;
    16 }
    17 void printList(struct ListNode * head){
    18     while(head != NULL){
    19         printf("Val: %d ",head->val,head->next);
    20         head = head->next;
    21     }
    22 }
    23 void addOneNode(struct ListNode * head,int val){
    24     struct ListNode * newNode  =(struct ListNode *)malloc(sizeof(struct ListNode));
    25     newNode->val = val;
    26     newNode->next = NULL;
    27 
    28     //遍历链表到 尾部
    29     struct ListNode * temp = head;
    30     while(temp->next !=NULL){
    31         temp = temp->next;
    32     }
    33     temp->next = newNode;
    34 }
    35 
    36 //链表逆序 (Leetcode 代码)
    37 struct ListNode * reverseList(struct ListNode * head){
    38     struct ListNode * pPre = NULL; //保存前一个地址
    39     struct ListNode * pNext = head->next; //保存下一个地址
    40     while(pNext != NULL){
    41         head->next = pPre; //
    42         pPre = head;
    43 
    44         head = pNext; //
    45         pNext = head->next;
    46     }
    47     head->next = pPre;  //这个是因为最后一个连不上,所以最后要自己连上!
    48     return head;
    49 }
    50 
    51 
    52 int main(){
    53 
    54     struct ListNode * head = ListInit();  //head存数据(默认存的值为0)
    55     head->val = 1; //这里将默认的head.val =0 变为1
    56     for(int i =2;i<10;++i){
    57         addOneNode(head,i);
    58     }
    59     printList(head);
    60     head = reverseList(head);
    61     printList(head);
    62 
    63     return 0;
    64 }
    19.10.3写

    面是老师的代码:

     1 class Solution {
     2 public:
     3     ListNode* reverseList(ListNode* head) {
     4         ListNode * newHead =NULL;
     5         while(head){
     6             ListNode *temp = head->next;
     7             head->next =newHead;
     8             newHead = head;
     9             
    10             head = temp;
    11         }
    12         return newHead;
    13         
    14     }
    15 };

    例1-b:链表逆序-b  (leetcode 编号 92)

    重要的四个结点:

     

     个人的思路:

     1 ListNode * reverseBetween(ListNode * head,int m,int n){
     2     if(head ==NULL || m==n) return head;
     3     int flag = 0;
     4     if(m==1)  flag = 1;
     5     ListNode* pCur = head;
     6     for(int i =0;i<m-2;++i){
     7         pCur = pCur->next;
     8     }//将pCur 遍历到 m前一个节点
     9 
    10     ListNode* pBackWard = pCur;  //记录
    11     ListNode* pM = pCur->next; //记录
    12     //开始逆序
    13     pCur = pM;
    14     if(flag) pCur = pBackWard; //特殊情景时修正下
    15     ListNode * pPre = NULL;
    16     for(int i =0;i<n-m;++i){
    17         ListNode * pNext = pCur->next;//本次
    18         pCur->next = pPre;//
    19         pPre = pCur; //下次
    20         pCur = pNext; //
    21     }
    22     if(!flag){
    23         pBackWard->next = pCur;
    24         ListNode * temp = pCur->next;
    25         pCur->next = pPre;
    26         pM->next = temp;
    27     }else{
    28         head = pCur;
    29         ListNode * temp = pCur->next;
    30         pBackWard->next = temp;
    31         head->next = pPre;
    32     }
    33     return head;
    34 }
    我自己的代码 只移动一个指针

    下面是老师的代码:

     1 #include <stdio.h>
     2 struct ListNode{
     3     int val;
     4     struct ListNode *next;
     5 };
     6 
     7 class Solution {
     8 public:
     9     ListNode* reverseBetween(ListNode* head, int m, int n) {
    10         ListNode * pre_head = NULL;
    11         ListNode * result = head; //最终返回的头节点
    12         // 向前移动m-1 个位置 ,pre_head  和 head 一起移动
    13         for (int i = 0; i < m - 1; ++i) {
    14             pre_head = head;
    15             head = head->next;
    16         }
    17 
    18         ListNode * modified_list_tail =head;
    19         ListNode * new_head  = NULL; //新的逆序链表的头
    20         int change_node_num = n-m+1;
    21         while(head &&change_node_num){
    22             ListNode * temp = head->next;
    23             head->next = new_head;
    24             new_head = head;
    25             head = temp;
    26 
    27             change_node_num--;
    28         }
    29         modified_list_tail->next = head;
    30 
    31         if(pre_head){
    32             pre_head->next = new_head;
    33         }
    34         else{  //如果是从第一个开始就逆序的话, 特殊情况!
    35             result = new_head;
    36         }
    37         return result;
    38     }
    39 };

    例2:求两个链表的交点(No.160):

     例2题目要求:

    注意:

    如果两个链表没有交点,返回 null.
    在返回结果后,两个链表仍须保持原有的结构。
    可假定整个链表结构中没有循环。
    程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

    方法一:

    必备知识(STL set的使用):

    使用set 求交集。  

     1 #include <iostream>
     2 using namespace std;
     3 
     4 #include <set>
     5 
     6 int main(){
     7 
     8     set<int> test_set;
     9     const int A_LEN = 7;
    10     const int B_LEN = 8;
    11 
    12     int a[A_LEN] = {5,1,4,8,10,1,3};
    13     int b[B_LEN] ={2,7,6,3,1,6,0,1};
    14 
    15     for (int i = 0; i < A_LEN; ++i) {
    16         test_set.insert(a[i]);  //将数组a  的元素插入到 set 中
    17     }
    18     for (int i = 0; i < B_LEN; ++i) {
    19         if(test_set.find(b[i]) != test_set.end()){
    20             printf("b[%d] = %d in array A 
    ",i,b[i]);
    21         }
    22     }
    23     return 0;
    24 }
    STL set 的基本使用

    方法一思路:使用set 求交集

     1 #include <iostream>
     2 using namespace std;
     3 
     4 #include <set>
     5 struct ListNode{
     6     int val;
     7     ListNode * next;
     8     ListNode (int x): val(x) ,next(NULL){
     9         //构造函数
    10     }
    11 };
    12 
    13 class Solution{
    14 public:
    15     ListNode * getIntersectionNode(ListNode * headA,ListNode *headB){
    16         set<ListNode *> node_set;
    17         while(headA){
    18             node_set.insert(headA);  //将 headA 加入到 set 中
    19             headA = headA->next;
    20         }
    21         while(headB){
    22             if(node_set.find(headB) != node_set.end()){
    23                 return headB;  //在node_set 找到 headB  此时返回
    24             }
    25             headB = headB->next;
    26         }
    27         return NULL;
    28     }
    29 };
    方法一

    但是,此时并不是最优的! 

    因为用到了集合,此时的时间复杂度是 nlog(n) , 空间复杂度是O(n)

    比较慢!!!

    方法二:

     思路2 :空间复杂度O(1):

    此时,我们最多遍历一个链表的长度,时间复杂度是O(n)  因为没有申请其他额外的空间,所以 空间复杂度为   O(1)

     1 #include <iostream>
     2 using namespace std;
     3 
     4 struct ListNode{
     5     int val;
     6     ListNode * next;
     7     ListNode (int x): val(x) ,next(NULL){
     8         //构造函数
     9     }
    10 };
    11 int get_list_length(ListNode * head){
    12     int len =0;
    13     while(head){
    14         len ++;
    15         head = head->next;
    16     }
    17     return len;
    18 }
    19 ListNode * forward_long_list(int long_len ,int short_len,ListNode *head){
    20     int delta = long_len - short_len;
    21     for (int i = 0; i < delta; ++i) {
    22         head = head->next;
    23     }
    24     return head;
    25 }
    26 
    27 class Solution{
    28 public:
    29     ListNode * getIntersectionNode(ListNode * headA,ListNode *headB){
    30         int list_A_len = get_list_length(headA);
    31         int list_B_len = get_list_length(headB);
    32 
    33         if(list_A_len > list_B_len){  //如果 A  的长度比 B的长
    34             headA = forward_long_list(list_A_len,list_B_len,headA);
    35         }else{
    36             headB = forward_long_list(list_B_len,list_A_len,headB);
    37         }
    38 
    39         //  一起向前走,如果headA == headB  即为交点
    40         while(headA && headB){
    41             if(headA == headB){
    42                 return headA;
    43             }
    44             headA = headA->next;
    45             headB = headB->next;
    46         }
    47         return NULL;
    48     }
    49 };
    方法二

    它就很快了!!!牛逼。

    例2:链表求环(No.142   (No.141)):

    思路1 :使用STL  set 求环起始节点:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 #include <set>
     5 struct ListNode{
     6     int val;
     7     ListNode * next;
     8     ListNode (int x): val(x) ,next(NULL){
     9         //构造函数
    10     }
    11 };
    12 
    13 class Solution{
    14 public:
    15     ListNode * detectCycle(ListNode *head){
    16         set <ListNode *> node_set;
    17         while (head){ //遍历链表
    18             if(node_set.find(head) != node_set.end()){ //此时在set 中找到了 head
    19                 return head;
    20             }
    21             node_set.insert(head);
    22             head = head->next;
    23         }
    24         return NULL;
    25     }
    26 };
    思路一

    缺点:太慢了!!!

    思路2 :快慢指针赛跑:

    它的思想和体育课上的跑步是一样的,赛道是环形的这样跑的快的人才有可能超过跑的慢的人!

    上图它可以确定有没有环,但是,它可能不是环的起始位置,

    下面是如何求环的起始位置:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 #include <set>
     5 struct ListNode{
     6     int val;
     7     ListNode * next;
     8     ListNode (int x): val(x) ,next(NULL){
     9         //构造函数
    10     }
    11 };
    12 
    13 class Solution{
    14 public:
    15     ListNode * detectCycle(ListNode *head){
    16         ListNode *fast = head; //快指针
    17         ListNode *slow = head; //慢指针
    18 
    19         ListNode *meet = NULL  ;//相遇的指针
    20         while (fast){
    21             slow = slow->next;  //slow  和 fast 各走一步
    22             fast = fast->next;
    23             if(!fast){ //如果fast 为空了
    24                 return NULL;
    25             }
    26             fast = fast->next; //fast 再走一步
    27             if(fast == slow){
    28                 meet = fast; // 相遇了
    29                 break;
    30             }
    31         }
    32         if(meet == NULL){
    33             return NULL;
    34         }
    35         while (head && meet){
    36             if(head == meet ){
    37                 return head;  //此时为起始节点
    38             }
    39             head = head->next;
    40             meet = meet->next;
    41         }
    42         return NULL;
    43     }
    44 };
    方法二

    leetcode No.141 的答案:

    方法一:

    使用STL 中的set  

     1 class Solution {
     2 public:
     3     bool hasCycle(ListNode *head) {
     4         set <ListNode *> node_set;
     5         while (head){ //遍历链表
     6             if(node_set.find(head) != node_set.end()){ //此时在set 中找到了 head
     7                 return true;
     8             }
     9             node_set.insert(head);
    10             head = head->next;
    11         }
    12         return false;
    13     }
    14 };
    使用STL

    方法二:

     1 class Solution {
     2 public:
     3     bool hasCycle(ListNode *head) {
     4         ListNode *fast = head; //快指针
     5         ListNode *slow = head; //慢指针
     6 
     7         while (fast){
     8             slow = slow->next;  //slow  和 fast 各走一步
     9             fast = fast->next;
    10             if(!fast){ //如果fast 为空了
    11                 return false;
    12             }
    13             fast = fast->next; //fast 再走一步
    14             if(fast == slow){
    15                 return true;
    16             }
    17         }
    18         return false;
    19     }
    20 };
    使用快慢指针

    例4:链表划分 No.86

    思路:巧用临时头结点:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 struct ListNode{
     5     int val;
     6     ListNode * next;
     7     ListNode (int x): val(x) ,next(NULL){
     8         //构造函数
     9     }
    10 };
    11 
    12 class Solution{
    13 public:
    14     ListNode * partition(ListNode * head,int x){
    15         ListNode less_head(0);  //设置两个临时头节点
    16         ListNode more_head(0);
    17         ListNode * less_ptr = &less_head;
    18         ListNode * more_ptr = &more_head;
    19 
    20         while(head){
    21             if(head->val <x){
    22                 less_ptr->next = head;
    23                 less_ptr = head;
    24             }else{
    25                 more_ptr->next = head;
    26                 more_ptr = head;
    27             }
    28 
    29             head = head->next;
    30         }
    31         less_ptr->next = more_head.next;
    32         more_ptr->next = NULL;
    33         return less_head.next;
    34     }
    35 };
    View Code

    例5:复杂链表的深度拷贝 No.138

    必备知识 (STL Map的使用):

    构造如下的链表:

     1 #include <stdio.h>
     2 #include <iostream>
     3 using namespace std;
     4 #include <map> //STL map的头文件
     5 
     6 struct RandomListNode{
     7     int label;
     8     RandomListNode * next, * random;
     9     RandomListNode(int x): label(x),next(NULL),random (NULL){};
    10 };
    11 
    12 
    13 int main(){
    14     map<RandomListNode *,int > node_map;  //map的 key 是 节点地址, value 是 id号
    15     RandomListNode a(5);
    16     RandomListNode b(3);
    17     RandomListNode c(6);
    18 
    19     a.next = &b;
    20     b.next = &c;
    21 
    22     a.random = &c;
    23     b.random = &a;
    24     c.random = &c;
    25 
    26     node_map[&a] = 1;
    27     node_map[&b] = 2;
    28     node_map[&c] = 3;
    29     cout << "a.random id ="<<node_map[a.random]<<endl;
    30     cout << "b.random id ="<<node_map[b.random]<<endl;
    31     cout << "c.random id ="<<node_map[c.random]<<endl;
    32 
    33 
    34 
    35     return 0;
    36 }
    37 /*
    38  * 输出:
    39  * a.random id =3
    40     b.random id =1
    41     c.random id =3
    42  * */
    map的基本使用

    思路及代码:

    最重要的是 上面的这两个map  , 第一个的key是节点地址 ,第二个的key 是id  .

    首先,遍历原链表,输入random 指针的值就知道,它指向的是哪个id ,

    然后,在新链表中,知道要指向哪个id时,就可以得到对应的节点地址。

     1 class Node {
     2 public:
     3     int val;
     4     Node* next;
     5     Node* random;
     6 
     7     Node() {}
     8 
     9     Node(int _val, Node* _next, Node* _random) {
    10         val = _val;
    11         next = _next;
    12         random = _random;
    13     }
    14 };
    15 class Solution {
    16 public:
    17     Node* copyRandomList(Node* head) {
    18         if(!head) return head;  //如果head 本身为空  直接返回
    19         map<Node*,int> node_map;
    20         vector <Node*> node_vec; //第二个map 本质是个数组
    21         Node* ptr = head;
    22 
    23         int i=0;
    24         while(ptr){
    25             node_vec.push_back(new Node(ptr->val,NULL,NULL));//将新链表的节点 加入到 node_vec 构造成一个 map,id是下标。
    26             node_map[ptr] = i; //构造原始链表的  node_map
    27             ptr = ptr->next;
    28             i++;
    29         }
    30         node_vec.push_back(0);  //为了下面next 连接最后一个的时候,给最后一个赋空
    31         ptr = head;
    32         i =0;  //再次遍历原始列表 ,连接新链表的next指针 和 random指针
    33         while(ptr){
    34             node_vec[i]->next = node_vec[i+1]; //连接新表的next
    35             if(ptr->random) { //当random 指针不空的时候
    36                 int id = node_map[ptr->random];
    37                 node_vec[i]->random = node_vec[id]; //连接新表的 random
    38             }
    39             ptr = ptr->next;
    40             i++;
    41         }
    42         return node_vec[0];
    43     }
    44 };
    版本一
     1 struct RandomListNode{
     2     int label;
     3     RandomListNode * next, * random;
     4     RandomListNode(int x): label(x),next(NULL),random (NULL){};
     5 };
     6 class Solution{
     7 public:
     8     RandomListNode * copyRandomList(RandomListNode * head){
     9         map<RandomListNode *,int> node_map;
    10         vector <RandomListNode * > node_vec; //第二个map 本质是个数组
    11         RandomListNode *ptr = head;
    12 
    13         int i=0;
    14         while(ptr){
    15             node_vec.push_back(new RandomListNode(ptr->label));//将新链表的节点 加入到 node_vec 构造成一个 map,id是下标。
    16             node_map[ptr] = i; //构造原始链表的  node_map
    17             ptr = ptr->next;
    18             i++;
    19         }
    20         node_vec.push_back(0);  //为了下面next 连接最后一个的时候,给最后一个赋空
    21         ptr = head;
    22         i =0;  //再次遍历原始列表 ,连接新链表的next指针 和 random指针
    23         while(ptr){
    24             node_vec[i]->next = node_vec[i+1]; //连接新表的next
    25             if(ptr->random) { //当random 指针不空的时候
    26                 int id = node_map[ptr->random];
    27                 node_vec[i]->random = node_vec[id]; //连接新表的 random
    28             }
    29             ptr = ptr->next;
    30             i++;
    31         }
    32         return node_vec[0];
    33     }
    34 };
    版本二(和一差不多)
     1 #include <stdio.h>
     2 #include <iostream>
     3 using namespace std;
     4 #include <map> //STL map的头文件
     5 #include <vector>
     6 
     7 struct RandomListNode{
     8     int val;
     9     RandomListNode * next, * random;
    10     RandomListNode(int x): val(x),next(NULL),random (NULL){};
    11 };
    12 class Solution{
    13 public:
    14     RandomListNode * copyRandomList(RandomListNode * head){
    15         map<RandomListNode *,int> node_map;
    16         vector <RandomListNode * > node_vec; //第二个map 本质是个数组
    17         RandomListNode *ptr = head;
    18 
    19         int i=0;
    20         while(ptr){
    21             node_vec.push_back(new RandomListNode(ptr->val));//将新链表的节点 加入到 node_vec 构造成一个 map,id是下标。
    22             node_map[ptr] = i; //构造原始链表的  node_map
    23             ptr = ptr->next;
    24             i++;
    25         }
    26         node_vec.push_back(0);  //为了下面next 连接最后一个的时候,给最后一个赋空
    27         ptr = head;
    28         i =0;  //再次遍历原始列表 ,连接新链表的next指针 和 random指针
    29         while(ptr){
    30             node_vec[i]->next = node_vec[i+1]; //连接新表的next
    31             if(ptr->random) { //当random 指针不空的时候
    32                 int id = node_map[ptr->random];
    33                 node_vec[i]->random = node_vec[id]; //连接新表的 random
    34             }
    35             ptr = ptr->next;
    36             i++;
    37         }
    38         return node_vec[0];
    39     }
    40 };
    41 
    42 int main(){
    43     map<RandomListNode *,int > node_map;  //map的 key 是 节点地址, value 是 id号
    44     RandomListNode a(5);
    45     RandomListNode b(3);
    46     RandomListNode c(6);
    47 
    48     a.next = &b;
    49     b.next = &c;
    50 
    51     a.random = &c;
    52     b.random = &a;
    53     c.random = &c;
    54 
    55     node_map[&a] = 1;
    56     node_map[&b] = 2;
    57     node_map[&c] = 3;
    58     cout << "a.random id ="<<node_map[a.random]<<endl;
    59     cout << "b.random id ="<<node_map[b.random]<<endl;
    60     cout << "c.random id ="<<node_map[c.random]<<endl;
    61 
    62     Solution * solution = new Solution();
    63     RandomListNode * res =  solution->copyRandomList(&a);
    64 
    65     while(res){
    66         cout<<"val = "<<res->val;
    67         if(res->random){
    68             cout<<" random地址中的val = "<<res->random->val<<endl;
    69         }else{
    70             cout<<" random地址中的val = NULL"<<endl;
    71         }
    72         res = res->next;
    73     }
    74     return 0;
    75 }
    带调试代码

    例6-a:排序链表的合并 No.21

    思路及代码:

     1 #include <iostream>
     2 using namespace std;
     3 /**
     4  * Definition for singly-linked list.
     5  * struct ListNode {
     6  *     int val;
     7  *     ListNode *next;
     8  *     ListNode(int x) : val(x), next(NULL) {}
     9  * };
    10  */
    11 struct ListNode {
    12     int val;
    13     ListNode *next;
    14     ListNode(int x) : val(x), next(NULL) {}
    15 };
    16 
    17 class Solution {
    18 public:
    19     ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    20         ListNode temp_head(0);
    21         ListNode *pre = &temp_head;
    22 
    23         while (l1 && l2) { //l1 和 l2 都不为空的时候遍历
    24             if (l1->val < l2->val) {
    25                 pre->next = l1;  //pre 指向  l1当前的节点
    26                 l1 = l1->next;
    27             } else {
    28                 pre->next = l2;
    29                 l2 = l2->next;
    30             }
    31             pre = pre->next;  //将新的链表的pre 向前移动
    32         }
    33 
    34         //如果 l1 有剩余
    35         if(l1){
    36             pre->next = l1;
    37         }
    38         //如果l2 有剩余
    39         if(l2){
    40             pre->next = l2;
    41         }
    42         return temp_head.next;
    43     }
    44 };
    View Code

    例6-b:排序链表的合并 (多个)No.23

    思路及代码:

    方案一:

    直接暴力!

    但是,这样是不行的,因为它的时间复杂度O(k^2 *n)太高了!是无法在LeetCode 上通过的 。

    下面看方案二:

    方案二:

    排序后相连

    vector  排序的时间复杂度最优是 nlog(n) 

    方案二的时间复杂度是 O(kn *log(kn))  ,  它和方案一比 当n 比较大时 方案二更好.....  

    这里我们排序使用STL 中的sort()  算法!  

    简单的例子(排序算法)

     1 #include <iostream>
     2 using namespace std;
     3 #include <vector>
     4 #include <algorithm>
     5 
     6 struct ListNode {
     7     int val;
     8     ListNode *next;
     9     ListNode(int x) : val(x), next(NULL) {}
    10 };
    11 
    12 bool cmp(const ListNode * a,const ListNode * b){
    13     return a->val < b->val;
    14 }
    15 int main(){
    16     ListNode a(3);
    17     ListNode b(4);
    18     ListNode c(0);
    19     ListNode d(1);
    20 
    21     vector <ListNode *> v;
    22     v.push_back(&a);
    23     v.push_back(&b);
    24     v.push_back(&c);
    25     v.push_back(&d);
    26 
    27     //调用std::sort 算法
    28     sort(v.begin(),v.end(),cmp);
    29     for (int i = 0; i < v.size(); ++i) {
    30         cout << v[i]->val;
    31     }
    32     return 0;
    33 }
    View Code
     1 #include <iostream>
     2 using namespace std;
     3 
     4 #include <vector>
     5 #include <algorithm>
     6 
     7 struct ListNode {
     8     int val;
     9     ListNode *next;
    10     ListNode(int x) : val(x), next(NULL) {}
    11 };
    12 
    13 bool cmp(const ListNode * a,const ListNode * b){
    14     return a->val < b->val;
    15 }
    16 class Solution {
    17 public:
    18     ListNode* mergeKLists(vector<ListNode*>& lists) {
    19         vector <ListNode *> node_vec;
    20         for (int i = 0; i < lists.size(); ++i) {
    21             ListNode * head = lists[i];
    22             while (head){
    23                 node_vec.push_back(head);
    24                 head = head->next;
    25             }
    26         }
    27         if (node_vec.size() == 0){
    28             return NULL;
    29         }
    30         sort(node_vec.begin(),node_vec.end(),cmp);  //根据节点数值进行排序
    31         for (int i = 0; i < node_vec.size() -1; ++i) {
    32             node_vec[i]->next = node_vec[i + 1];  //将排序好的节点首尾相连
    33         }
    34         node_vec[node_vec.size()-1] ->next = NULL;
    35         return node_vec[0];
    36     }
    37 };
    方案二的解法!!!

    方案三:

    分治!!!!!

    这里的log 都是以2为底的对数  。。。  

      1 #include <iostream>
      2 using namespace std;
      3 
      4 #include <vector>
      5 #include <algorithm>
      6 
      7 struct ListNode {
      8     int val;
      9     ListNode *next;
     10     ListNode(int x) : val(x), next(NULL) {}
     11 };
     12 bool cmp(const ListNode *a,const ListNode *b){
     13     return a->val < b->val;
     14 }
     15 
     16 ListNode * mergeTwoLists(ListNode *l1,ListNode *l2){
     17     if(l1 == NULL &&l2 ==NULL){
     18         return NULL;
     19     }
     20     if(l1 == NULL){
     21         return l2;
     22     }
     23     if(l2 == NULL){
     24         return l1;
     25     }
     26     vector <ListNode *> node_vec;
     27     while(l1){
     28         node_vec.push_back(l1);
     29         l1 = l1->next;
     30     }
     31     node_vec[node_vec.size() -1]->next =l2; //将两个链 连接起来
     32     while(l2){
     33         node_vec.push_back(l2);
     34         l2 = l2->next;
     35     }
     36     sort(node_vec.begin(),node_vec.end(),cmp);
     37     //将排序好的节点 首尾 相连
     38     for (int i = 0; i < node_vec.size() -1; ++i) {
     39         node_vec[i]->next = node_vec[i+1];
     40     }
     41     node_vec[node_vec.size()-1]->next = NULL;
     42     return node_vec[0];  //vector 只是个容器,它不负责将里面的东西相连
     43 }
     44 
     45 
     46 class Solution {
     47 public:
     48     ListNode* mergeKLists(vector<ListNode*>& lists) {
     49         if(lists.size() == 0){
     50             return NULL;
     51         }
     52         if(lists.size() ==1){
     53             return lists[0];
     54         }
     55         if(lists.size() == 2 ){ //如果只有两个链表
     56             return mergeTwoLists(lists[0],lists[1]);
     57         }
     58         int mid = lists.size()/2;
     59 
     60         vector <ListNode *> sub1_lists;
     61         vector <ListNode *> sub2_lists; //拆分lists 为两个子lists
     62 
     63         for (int i = 0; i < mid; ++i) {
     64             sub1_lists.push_back(lists[i]);
     65         }
     66         for (int i = mid; i < lists.size(); ++i) {
     67             sub2_lists.push_back(lists[i]);
     68         }
     69         ListNode * l1 = mergeKLists(sub1_lists); //递归调用
     70         ListNode * l2 = mergeKLists(sub2_lists);
     71 
     72         return mergeTwoLists(l1,l2); //分治
     73     }
     74 };
     75 
     76 int main() {
     77 
     78     ListNode a(1);
     79     ListNode b(10);
     80     ListNode c(9);
     81     ListNode d(7);
     82     ListNode e(92);
     83     ListNode f(5);
     84     ListNode g(24);
     85     ListNode h(16);
     86 
     87     a.next = &b;
     88     b.next = &c;
     89 
     90     d.next = &e;
     91     e.next = &f;
     92 
     93     g.next = &h;
     94 
     95     Solution solve;
     96 
     97     vector<ListNode *> lists;
     98     lists.push_back(&a);
     99     lists.push_back(&d);
    100     lists.push_back(&g);
    101 
    102     ListNode *head = solve.mergeKLists(lists);
    103 //    ListNode * head = mergeTwoLists(lists[0],lists[1]);
    104     while (head) {
    105         cout << head->val << endl;
    106         head = head->next;
    107     }
    108     return 0;
    109 }
    这里使用分治!!!

    但是提交之后,发现还不如方案二!!!。

  • 相关阅读:
    祝好,又十年
    关于简书的吐槽与思考还有杂七杂八负面情绪宣泄
    康威生命游戏———孤独会致命,拥挤也一样(转载)
    Bran的内核开发教程(bkerndev)-07 中断描述符表(IDT)
    Ubuntu安装QQ
    Bran的内核开发教程(bkerndev)-06 全局描述符表(GDT)
    Ubuntu安装scrcpy手机投屏和控制(Ubuntu用QQ微信的另一种方法)
    C、C++的Makefile模板
    C语言打印当前所在函数名、文件名、行号
    Bran的内核开发教程(bkerndev)-05 打印到屏幕
  • 原文地址:https://www.cnblogs.com/zach0812/p/11480529.html
Copyright © 2020-2023  润新知