链表 leetcode题目总结 c++

链表

链表和数组最大的区别在于,链表不支持随机访问,不像数组可以对任意一位的数据进行访问,链表只能从头一个一个往下访问,寻找下一个元素,像穿针引线似的。也正因为链表的这种特点,增大了链表题目的难度。

本文主要讨论的是单链表,单链表中的链表结点结构体定义如下

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

由上面的代码可以看出,每个结点包含两个域,一个是val表示结点的值,一个是next指针,指向下一个结点。

1)做链表类题目的关键是画图,将链表指针指向的内存的变化用图表示出来。
2)链表类题目还有一个重要的技巧是设置虚拟头结点。在做题的时候,头结点(head)常常要特殊处理,因为head结点没有前一个结点,这就决定了头节点和后续节点的处理方法不同。但是如果在头结点前加了一个虚拟头节点,那它就可以用正常的方法来处理了。

虚拟头节点定义如下:

ListNode* dummyHead = new ListNode(0); //新建一个结点,value为0
dummyHead->next = head; //让它next指针指向头结点
虚拟头结点
相关题目
  • leetcode #21. Merge Two Sorted Lists 合并两个链表
  • leetcode #206. Reverse Linked List 翻转链表
  • leetcode #92. Reverse Linked List II 翻转链表中指定区间的结点
  • leetcode #83. Remove Duplicates from Sorted List 删除链表中重复元素
  • leetcode #2. Add Two Numbers 将两个链表转化成整数并相加,再存入链表中
  • leetcode #445. Add Two Numbers II** 和上题类似,但更难一些
  • leetcode #237. Delete Node in a Linked ListDelete Node in a Linked List 删除指定结点
  • leetcode #328. Odd Even Linked List 奇偶链表
  • leetcode #19. Remove Nth Node From End of List 删除倒数第n个结点

leetcode #21. Merge Two Sorted Lists 合并两个链表
题目:Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
Example:
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == NULL) return l2;
        if(l2 == NULL) return l1;
        if(l1->val > l2->val){
            ListNode *tmp = l2;
            tmp->next = mergeTwoLists(l1, l2->next);
            return tmp;
        }
        else{
            ListNode *tmp = l1;
            tmp->next = mergeTwoLists(l1->next, l2);
            return tmp;
        }
    }
};

leetcode #206. Reverse Linked List 反转列表
思路:一般链表的题目都会约束不能对链表的值进行操作,只能对链表的结点进行操作。处理链表问题,需要多用几个指针来存储结点信息。

leetcode206

在链表中,一旦访问链表中的某一个域,一定要保证这个域不为空,为了避免这个问题,可以在刚开始的判断一下该链表是否为空。

Solution:

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* cur = head;
        ListNode* pre = NULL;
        while(cur!= NULL){
            ListNode* next = cur->next;

            cur->next = pre;
            pre = cur;
            cur = next;
        }

        return pre;
    }
};

leetcode #92. Reverse Linked List II 翻转链表中指定区间的结点
一定要画图!题目要求one-pass,所以遍历的时候要保存四个结点:m前一个node, 第m个node, 第n个node,第n+1个node;

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if (head == NULL or head->next == NULL)
            return head;
            
        ListNode *dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode *pre = dummyHead;
        ListNode *cur = head;
        int pos = 1;
        while (pos < m) {
            pre = cur;
            cur = cur->next;
            ++pos;
        }
        ListNode *preNode = pre; //m-1 node
        ListNode *curNode = cur; //m node
        
        // cur -> Node_m
        while (pos <= n) {
            ListNode *next = cur->next; 
            cur->next = pre;
            pre = cur;
            cur = next;
            ++pos;
        }
        preNode->next = pre; // m - 1 -> n
        curNode->next = cur; // m -> n + 1
        return dummyHead->next;
    }  
};

leetcode #83. Remove Duplicates from Sorted List 删除链表中重复元素
无非就是在遍历的时候,用三个指针来保存结点:previous, current, next;

class Solution {
public:
    
    ListNode* deleteDuplicates(ListNode* head) {
        if(head == NULL || head->next == NULL) return head;
        ListNode* pre = head;
        ListNode* cur = pre->next;
        
        while(cur != NULL)
        {
            if(cur->val == pre->val)
            {
                
                if(cur->next == NULL)
                {
                    
                    pre->next = cur->next;
                    return head;
                }
                else
                {
                    cur = cur->next;
                    pre->next = cur;
                }
            }
            else
            {
                pre = cur;
                cur = cur->next;
            }
        }
        return head;
    }
};

leetcode #2. Add Two Numbers 相加,再存入链表中
这题不能用一个整数来保存然后再相加,因为会出现溢出的情况;下面的答案是逐位相加,将进位保存

class Solution {
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
        ListNode *head = new ListNode(0);
        ListNode *cur = head;
        
        int extra = 0;
        while(l1 || l2 || extra)
        {
            int sum = (l1?l1->val:0) + (l2?l2->val:0) + extra;
            extra = sum/10;
            l1 = l1?l1->next:l1;
            l2 = l2?l2->next:l2;
            cur->next = new ListNode(sum%10);
            cur = cur->next;
            cout<<sum<<endl;
        }
        return head->next;
    }
};

leetcode #445. Add Two Numbers II
和#2题类似,但是难了很多。如果把链表翻转之后,就转换成了2,把加完之后的链表再翻转就是想要的答案了。所以该题是83和2的结合。

class Solution {
public:
    ListNode* reverse(ListNode* head)
    {
        ListNode* pre = NULL;
        ListNode* cur = head;
        if(cur == NULL) return head;
        while(cur != NULL) {
            ListNode* next = cur->next;
            
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
    
    
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        l1 = reverse(l1);
        l2 = reverse(l2);
        
        ListNode head(0);
        ListNode* cur = &head;
        int extra = 0;
        
        while(l1 || l2 || extra){
            
            int sum = (l1?l1->val:0 )+(l2?l2->val:0) + extra;
            extra = sum/10;
            l1 = l1?l1->next:0;
            l2 = l2?l2->next:0;
            cur->next = new ListNode(sum%10);
            cur = cur->next;
        }
        cur = reverse(head.next);
        return cur;
    }
};

leetcode #237. Delete Node in a Linked ListDelete Node in a Linked List 删除指定结点
注意本题是删除指定节点,而不是指定值
思路:由于指定节点前一个节点无法得到,所以就将下一个元素的值覆盖该节点,然后将下一个节点删除。一般情况下,我们对链表操作时,都不改变节点的值,只对节点本身操作。但是这题是特殊情况,所以链表问题不一定都是穿针引线的题
易错点:要考虑删除节点的下一个节点为空的情况,这种情况直接删掉该元素就可以了。

class Solution {
public:
    void deleteNode(ListNode* node) {
        if(node == NULL) return;
        if(node->next == NULL) {
            delete node;
            return;
        }
        node->val = node->next->val;
        
        ListNode* delNode = node->next;
        node->next = delNode->next;
        delete delNode;
        return;
        
    }
};

leetcode #328. Odd Even Linked List 奇偶链表

class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if(head == NULL || head->next == NULL) return head;
        if(head->next->next == NULL) return head;
        ListNode* preOdd = head;
        ListNode* preEven = head->next;
        ListNode* odd = head->next->next;
       
        //目前肯定有>=3个节点
        ListNode* even = head->next->next->next;
        preOdd->next = odd;
        odd->next = preEven;
        
        preEven->next = even;
        if(preEven->next == NULL){
            return preOdd;
        }
        
        //目前肯定有4个节点;
        int i = 1;

        ListNode* cur = even->next; //第5个节点
        
        while(cur != NULL)
        {
            if(i%2 != 0)
            {
                
                odd->next = cur;
                cur = cur->next;
                odd = odd->next;
                odd->next = preEven;
                
            }
            else
            {
                even->next = cur;
                cur = cur->next;
                even = even->next;
                even->next = NULL;
            }
            i++;
        }
        
        even->next = NULL;
        return preOdd;
    }
};

leetcode #19. Remove Nth Node From End of List 删除倒数第n个结点
删除指定倒数第n个元素
思路:解法1)就是two-pass;第一遍遍历链表长度,第二遍删除元素
解法2)保存p节点和q节点,p和q之间对节点数刚好为n,相当于一个滑动窗口,不断往后移动,直到q节点移动到空节点时,这时p节点指向的节点时倒数n个节点的前一个节点
易错点:弄清题目中的n是从0开始还是从1开始算的;在这题中n是从1开始数,并且n是合法的

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        
        ListNode* p = dummyHead;
        ListNode* cur = head;
        while(n--)
        {
            cur = cur->next;
        }
        ListNode* q = cur;
        while(q != NULL)
        {
            p = p->next;
            q = q->next;
        }
        
        ListNode* delNode = p->next;
        p->next = delNode->next;
        delete delNode;
        return dummyHead->next;
    }
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容