[算法专题] LinkedList

前段时间在看一本01年出的旧书《effective Tcp/Ip programming》,这个算法专题中断了几天,现在继续写下去。

Introduction

对于单向链表(singly linked list),每个节点有?个next指针指向后一个节点,还有一个成员变量用以储存数值;对于双向链表(Doubly LinkedList),还有一个prev指针指向前一个节点。与数组类似,搜索链表需要O(n)的时间复杂度,但是链表不能通过常数时间读取第k个数据。链表的优势在于能够以较?的效率在任意位置插?或删除一个节点。

Dummy Node,Scenario: When the head is not determinated

之前在博客中有几篇文章,已经介绍了Dummy Node的使用,实际上Dummy Node就是所谓的头结点,使用Dummy Node可以简化操作,统一处理head与其他node的操作。

链表操作时利?用dummy node是?一个?非常好?用的trick:只要涉及操作head节点,不妨创建dummy node:

ListNode *dummy = new ListNode(0);
dummy->next = head;

废话少说,来看以下几道题:

1. Remove Duplicates from Sorted List I, II

2. Merge Two Sorted Lists

3. Partition List

4. Reverse Linked List I,II

1. Remove Duplicates from Sorted List I

https://leetcode.com/problems/remove-duplicates-from-sorted-list/

Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,

Given 1->1->2, return 1->2.

Given 1->1->2->3->3, return 1->2->3.

这题我们的策略遇到重复的node,保留第一个,删除后面的,因此并不会改动head节点,所以下面的代码没有设置dummy node。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == NULL) {
            return head;
        }

        ListNode *headBak = head;
        while (head->next) {
            if (head->val == head->next->val) {
                // 保留第一个,删除后面的
                ListNode *tmp = head->next;
                head->next = tmp->next;
                delete tmp;
            } else {
                head = head->next;
            }
        }

        return headBak;
    }
};

2. Remove Duplicates from Sorted List II

https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,

Given 1->2->3->3->4->4->5, return 1->2->5.

Given 1->1->1->2->3, return 2->3.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == NULL) {
            return head;
        }

        ListNode *dummy = new ListNode(0);
        dummy->next = head;

        ListNode *pos = dummy;

        // 至少需要head 和 head->next 才可能有重复
        while (pos->next && pos->next->next) {
            if (pos->next->val == pos->next->next->val) {
                int preVal = pos->next->val;
                // 至少保证有两个node,才会有重复
                while (pos->next && pos->next->val == preVal) {
                    ListNode *tmp = pos->next;
                    pos->next = tmp->next;
                    delete tmp;
                }
            } else {
                pos = pos->next;
            }
        }

        return dummy->next;
    }
};

3. Merge Two Sorted Lists

https://leetcode.com/problems/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.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *dummy = new ListNode(0);
        ListNode *curr = dummy;

        while (l1 && l2) {
            if (l1->val < l2->val) {
                curr->next = l1;
                l1 = l1->next;
            } else {
                curr->next = l2;
                l2 = l2->next;
            }

            curr = curr->next;
        }

        if (l1) {
            curr->next = l1;
        }

        if (l2) {
            curr->next = l2;
        }

        return dummy->next;
    }
};

4. Partition List

https://leetcode.com/problems/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.

/**
 * 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 *leftDummy = new ListNode(0);
        ListNode *left = leftDummy;

        ListNode *rightDummy = new ListNode(0);
        ListNode *right = rightDummy;

        ListNode *curr = head;

        while (curr) {
            if (curr->val < x) {
                left->next = curr;
                left = left->next;
                curr = curr->next;
            } else {
                right->next = curr;
                right = right->next;
                curr = curr->next;
            }
        }

        left->next = rightDummy->next;
        right->next = NULL;

        return leftDummy->next;
    }
};

Basic Skills

5. Reverse Linked List

https://leetcode.com/problems/reverse-linked-list/

Reverse a singly linked list.

Hint:

A linked list can be reversed either iteratively or recursively. Could you implement both?

非递归写法如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == NULL) {
            return NULL;
        }

        ListNode *pre = NULL;
        ListNode *curr = head;
        ListNode *next = NULL;
        while (curr) {
            next = curr->next;

            curr->next = pre;
            pre = curr;

            curr = next;
        }

        return pre;
    }
};

递归写法如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *reverseList(ListNode *head) {
        // empty list
        if (head == NULL) return head;
        // Base case
        if (head->next == NULL) return head;

        // reverse from the rest after head
        ListNode *newHead = reverseList(head->next);
        // reverse between head and head->next
        head->next->next = head;
        // unlink list from the rest
        head->next = NULL;

        return newHead;
    }
};

6. Reverse Linked List II

https://leetcode.com/problems/reverse-linked-list-ii/

Reverse a linked list from position m to n. Do it in-place and in one-pass.

For example:

Given 1->2->3->4->5->NULL, m = 2 and n = 4,

return 1->4->3->2->5->NULL.

Note:

Given m, n satisfy the following condition:

1 ≤ mn ≤ length of list.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if (head == NULL) {
            return NULL;
        }

        ListNode *dummy = new ListNode(0);
        dummy->next = head;
        ListNode *pos = dummy;

        for (int i = 0; i <= m - 2; i++) {
            pos = pos->next;
        }
        ListNode *mPreNode = pos;
        ListNode *mCurrNode = pos->next;

        ListNode *nPreNode = NULL;
        ListNode *nCurrNode = mCurrNode;
        ListNode *nNextNode = NULL;
        for (int i = m; i <= n; i++) {
            nNextNode = nCurrNode->next;

            nCurrNode->next = nPreNode;
            nPreNode = nCurrNode;

            nCurrNode = nNextNode;
        }

        mPreNode->next = nPreNode;
        mCurrNode->next = nCurrNode;

        return dummy->next;
    }
};

7. Remove Linked List Elements

https://leetcode.com/problems/remove-linked-list-elements/

Remove all elements from a linked list of integers that have value val.

Example

Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6

Return: 1 --> 2 --> 3 --> 4 –> 5

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *dummy = new ListNode(0);
        dummy->next = head;

        ListNode *pre = dummy;
        ListNode *curr = head;
        while (curr) {
            if (curr->val == val) {
                ListNode *waitForDel = curr;

                pre->next = curr->next;
                curr = curr->next;

                delete waitForDel;
            } else {
                pre = pre->next;
                curr = curr->next;
            }
        }

        return dummy->next;
    }
};

8. Remove Nth Node From End of List

https://leetcode.com/problems/remove-nth-node-from-end-of-list/

Given a linked list, remove the nth node from the end of list and return its head.

For example,

   Given linked list: 1->2->3->4->5, and n = 2.

   After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Try to do this in one pass.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *dummy = new ListNode(0);
        dummy->next = head;

        ListNode *slow = dummy;
        ListNode *fast = dummy;
        for (int i = 0; i < n - 1; i++) {
            fast = fast->next;
        }

        ListNode *pre = NULL;
        while (fast->next) {
            pre = slow;
            slow = slow->next;
            fast = fast->next;
        }

        pre->next = slow->next;
        delete slow;

        return dummy->next;
    }
};

9. Remove Duplicates from Sorted List

https://leetcode.com/problems/remove-duplicates-from-sorted-list/

Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,

Given 1->1->2, return 1->2.

Given 1->1->2->3->3, return 1->2->3.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode *pos = head;
        while (pos) {
            if (pos->next && pos->val == pos->next->val) {
                ListNode *waitForDel = pos->next;
                pos->next = pos->next->next;
                delete waitForDel;
            } else {
                pos = pos->next;
            }
        }

        return head;
    }
};

/**
 *
class Solution {
public:
        ListNode *deleteDuplicates(ListNode *head) {
        if (head == NULL) {
            return NULL;
        }

        ListNode *node = head;
        while (node->next != NULL) {
            if (node->val == node->next->val) {
                ListNode *temp = node->next;
                node->next = node->next->next;
                delete temp;
            } else {
                node = node->next;
            }
        }

        return head;
    }
};
 *
 */

10. Remove Duplicates from Sorted List II

https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,

Given 1->2->3->3->4->4->5, return 1->2->5.

Given 1->1->1->2->3, return 2->3.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (head == NULL) {
            return head;
        }

        ListNode *dummy = new ListNode(0);
        dummy->next = head;

        ListNode *pos = dummy;

        // 至少需要head 和 head->next 才可能有重复
        while (pos->next && pos->next->next) {
            if (pos->next->val == pos->next->next->val) {
                int preVal = pos->next->val;
                // 至少保证有两个node,才会有重复
                while (pos->next && pos->next->val == preVal) {
                    ListNode *tmp = pos->next;
                    pos->next = tmp->next;
                    delete tmp;
                }
            } else {
                pos = pos->next;
            }
        }

        return dummy->next;
    }
};

(待续)

8

8

8

时间: 2024-08-08 02:21:30

[算法专题] LinkedList的相关文章

【枚举算法Day1】20170529-2枚举算法专题练习

20170529-2枚举算法专题练习 青岛二中日期 序号 题目名称 输入文件名 输出文件名 时限 内存 算法 难度 分类 081113 1 最大矩形 rectangle.in rectangle.out 1s 256MB 枚举 1 02枚举 081031 2 回文 palin.in palin.out 1s 256MB 枚举.优化 1 02枚举 081008 3 问题的设置 problemsetter.in problemsetter.out 1s 256MB 排序+枚举 1 02枚举 0810

图的算法专题——最短路径

概要: Dijkstra算法 Bellman-Ford算法 SPFA算法 Floyd算法 1.Dijkstra算法用于解决单源最短路径问题,严格讲是无负权图的最短路径问题. 邻接矩阵版 1 const int maxv=1000; 2 const int INF=1000000000; 3 int n,G[maxv][maxv]; 4 int d[maxv]; //起点到各点的最短路径长度 5 bool vis[maxv]={false}; 6 7 void Dijkstra(int s){ /

最短路径算法专题1----弗洛伊德

由于最短路径算法我认为比较重要,所以分成几个专题来慢慢细化去磨它,不能一口气吃个胖子嘛. 首先在说算法之前,先说清楚什么叫做最短路径. 题目一般会给你一张图,然后告诉你很多地方,然后告诉你各个地方之间的路程有多远,要你求出,两点间的最短距离,注意,题目给出的两点间的距离未必是最短的,可能通过第三个点转换之后达到更短.实际其实也是这样的,有时候两个地方并没有直线的道路只有曲线的绕路. 算法的思路: 1.用二维数组列出所有的距离,达到不了的用最大距离表示,如9999999 2.循环数组上面的每一个点

括号匹配问题 -算法专题

算法数据结构面试分享 符号匹配问题 今天在帖子上看见有同学在问,如果一个字符串中包含大括号和小括号,我们该如何解决括号匹配问题.我们今天就一起看下这道题吧.按照我们之前的套路,按部就班来: 确保我们理解了问题,并且尝试一个例子,确认理解无误. 举个例子,这样的括号是匹配的, ().{}.({}), ({()}(){}), 而类似于{(.{,({)都是不匹配的. 想想你可以用什么方法解决问题,你会选择哪一种,为什么? 我们拿这个字符串为例,({()}(){}), 最后一个)匹配的是第一个(, 倒数

ACM&amp;OI 基础数学算法专题

[前言] 本人学习了一定时间的算法,主要精力都花在数学类的算法上面 而数学类的算法中,本人的大部分精力也花费在了数论算法上 此类算法相对抽象,证明过程比较复杂 网络上的博客有写得非常好的,但也有写得不明所以的 因此,本人特此开一个新的专题,专门负责讲解一些比较基础的数学类算法 但本人知识面也有限,部分算法也还未掌握.因此,希望本专题也能促进本人学习这些算法 下面做出对更新的一些规定: 基本上保持每日更新一贴 对标注(已完结)的贴子,表明本贴子已完结 对标注(正在更新)的贴子,表明正在更新本贴 对

KM算法专题

原文:http://972169909-qq-com.iteye.com/blog/1184514 题目地址:这里. 1)求图中所有环的总长度(环的长度不唯一)的最小值.当无法得到完备匹配时说明环不存在. 第三题:http://acm.hdu.edu.cn/showproblem.php?pid=1853 直接建图,注意有重边哦! if (-c > w[a][b])     w[a][b] = -c; 当木有完美匹配输出-1 第四题:http://acm.hdu.edu.cn/showprobl

最短路径算法专题2----Dijkstra

这个算法适用于求单源最短路径,从一点出发,到其余个点的最短路径. 算法要点: 1.用二维数组存放点到点的距离-----不能相互到达的点用MAX代替距离 2.用dis数组存放源点到任意其他一点的距离----dis[5]表示源点到5点的距离为dis[5]中的值 3.用book数组记录已经确定最小dis的点 4.用index和indexNumber存放估计值的点 5.从源点到这个点如果比中间加上估计值的点还要长,就松弛 算法模型: for(循环N次) { for(循环找到估计值点) { 估计值点是现在

排序算法专题

数据结构课程可能会考到的排序算法: 插入排序 希尔排序 冒泡法 快排 选择排序 堆排序 归并排序 一 插入排序 #include<cstdio> #include<string> #include<cstring> #include<iostream> using namespace std; void print(int a[], int n ,int i) { cout<<i <<":"; for(int j=

【枚举算法Day1】20170529-2枚举算法专题练习 题解

1.OneMoreRectangle 一个矩形 ●如果任意枚举矩形坐标,显然不可行.数组太大,开不下!●我们注意到,如果我们放入了矩形,矩形周围并没有其它矩形,那么稍微移动这个矩形,不会改变答案.显然,一定存在一种方案,使得放入的矩形的边界与某些已知矩形边界重合.我们不妨规定,放入的矩形下边界必须与已知矩形重合.左边界必须与已知矩形重合. 所以就可以做了 1 type rec=record 2 x1,y1,x2,y2:longint; 3 end; 4 var n,x,y,i,j,k,ans,m