Leetcode题解-算法-链表

1、找出两个链表的交点

160. Intersection of Two Linked Lists(Easy)
给两个链表,找出链表的交点,没有交点输出NULL。
在这里插入图片描述
设置指针 l1 指向链表 A 头节点,当访问到链表 A 的尾节点时,从链表 B 头部开始访问。
设置指针 l2 指向链表 B 头节点,当访问到链表 B 的尾节点时,从链表 A 头部开始访问。

设链表 A 的长度为 a + c,链表 B 的长度为 b + c,访问到节点时,指针 l1 走过的距离为 a+c+b,指针 l2 走过的距离为 b+c+a。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *l1=headA;
        ListNode *l2=headB;
        while(l1!=l2)
        {
            l1=(l1==NULL)?headB:l1->next;
            l2=(l2==NULL)?headA:l2->next;
        }
        return l1;
    }
};

2、链表反转

206. Reverse Linked List(Easy)

Example:

Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL

递归。

/**
 * 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||head->next==NULL)
            return head;
        ListNode* tmp=head->next;
        ListNode*newhead=reverseList(head->next);
        tmp->next=head;
        head->next=NULL;
        return newhead;
    }
};

字符串原地反转:
定义三个指针 pre, cur, nex,每次将 cur->next 改为 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) {
        if(head==NULL||head->next==NULL)
            return head;
        ListNode* pre=NULL, *cur=head;
        while(cur!=NULL)
        {
            ListNode* nex=cur->next;
            cur->next=pre;
            pre=cur;
            cur=nex;
        }
        return pre;
    }
};

3、归并两个有序链表

21. Merge Two Sorted Lists(Easy)
Example:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

方法一:每次找两个链表中较小的值加入新的链表,直到有一个链表遍历结束,未结束的那个链表,将剩余的部分连到新链表的尾部。

/**
 * 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) {
        if(l1==NULL) return l2;
        if(l2==NULL) return l1;
        
        ListNode* head=new ListNode(1);		//创建一个新结点
        ListNode* tail=head;
        while(l1 && l2)
        {
            if(l1->val<l2->val)
            {
                tail->next=l1;
                l1=l1->next;
            }
            else
            {
                tail->next=l2;
                l2=l2->next;
            }
            tail=tail->next;
        }
        if(l1!=NULL)
            tail->next=l1;
        else
            tail->next=l2;
        return head->next;
    }
};

方法二:递归

/**
 * 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) {
        if(l1==NULL) return l2;
        if(l2==NULL) return l1;
        if(l1->val<l2->val)
        {
            l1->next=mergeTwoLists(l1->next,l2);
            return l1;
        }
        else
        {
            l2->next=mergeTwoLists(l1,l2->next);
            return l2;
        }
    }
};

4、从有序链表中删除重复结点

83. Remove Duplicates from Sorted List(Easy)
Given a sorted linked list, delete all duplicates such that each element appear only once.

Example 1:

Input: 1->1->2
Output: 1->2

Example 2:

Input: 1->1->2->3->3
Output: 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 *pre=head,*cur=head;
        while(pre!=NULL)
        {
            while(cur!=NULL && cur->val==pre->val)
                 cur=cur->next;
            
            pre->next=cur;
            pre=cur;
        }
        return head;
    }
};

5、删除链表中倒数第 n 个结点

19. Remove Nth Node From End of List(Medium)
Given a linked list, remove the n-th node from the end of list and return its head.

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.

问题分析:
两个指针 fast,slow,先让 fast 走 n 步,让后二者一起走,直到 fast->next==NULL,此时 slow 指向倒数第 n+1个结点。

注意:如果 fast 先走 n 步后,发现 fast->next==NULL,表示删除头节点。

/**
 * 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 *fast=head,*slow=head;
        for(int i=0;i<n;i++)
            fast=fast->next;
        if(fast==NULL)		//删除的是第一个结点
            return head->next;
        while(fast->next!=NULL)
        {
            fast=fast->next;
            slow=slow->next;
        }
        slow->next=slow->next->next;
        return head;
    }
};

6、交换链表中相邻的结点

24. Swap Nodes in Pairs(Medium)
Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list’s nodes, only nodes itself may be changed.

Example:

Given 1->2->3->4, you should return the list as 2->1->4->3.

问题分析
不能只换结点的值。
在这里插入图片描述

/**
 * 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 *fast=head->next,*slow=head;
        ListNode *pre=new ListNode(-1);
        pre->next=slow;
        head=fast;     
        while(1)
        {
            slow->next=fast->next;
            fast->next=slow;
            pre->next=fast;
            pre=slow;
            slow=slow->next;
            if(slow==NULL)
                return head;
            fast=slow->next;
            if(fast==NULL)
                return head;
        }
    }
};

7、两链表的和

445. Add Two Numbers II(Medium)
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Follow up:
What if you cannot modify the input lists? In other words, reversing the lists is not allowed.

Example:

Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7

不能修改原始链表

问题分析:
由于链表相加需要右端对其,链表不能从后向前访问,所以需要将链表的值放到栈中,使其右端的值对其,再将每一位相加,注意:这里相加之和大于 10 需要向该节点的前一结点进位。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack<int>s1;
        stack<int>s2;
        stack<int>res;
        for(ListNode *it=l1;it!=NULL;it=it->next)
            s1.push(it->val);
        for(ListNode *it=l2;it!=NULL;it=it->next)
            s2.push(it->val);
        int cur=0;              //表示当前位的值,大于10需要进位
        while(!s1.empty()&&!s2.empty())//从过后向前把两链表的和压入栈中
        {
            cur+=s1.top()+s2.top();
            s1.pop();
            s2.pop();
            res.push(cur%10);
            cur=cur/10;
        }
        while(!s1.empty())      //如果 l1 比 l2 更长,把剩的值压入栈
        {
            cur+=s1.top();
            s1.pop();
            res.push(cur%10);
            cur=cur/10;
        }
        while(!s2.empty())      //如果 l2 比 l1 更长,把剩的值压入栈
        {
            cur+=s2.top();
            s2.pop();
            res.push(cur%10);
            cur=cur/10;
        }
        while(cur>0)            //有进位
        {
            res.push(cur%10);
            cur=cur/10;
        }
        ListNode*head=new ListNode(res.top());//构建新的链表
        ListNode*tail=head;
        res.pop();
        while(!res.empty())
        {
            ListNode*tmp=new ListNode(res.top());
            res.pop();
            tail->next=tmp;
            tail=tmp;
        }
        tail->next=NULL;
        return head;
    }
};

下面这种方法为翻转两链表,这样保证链表右端对齐,再相加。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *revese(ListNode *head){
        if(head == NULL || head->next == NULL)
            return head;
        ListNode *pre = NULL, *cur = head;
        while(cur){
            ListNode *next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
    
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode *newl1 = revese(l1);
        ListNode *newl2 = revese(l2);
        ListNode *head = new ListNode(-1);
        ListNode *tail = head;
        int cur = 0;
        while (newl1 && newl2){
            cur = cur + newl1->val + newl2->val;
            ListNode *tmp = new ListNode(cur%10);
            tail ->next = tmp;
            tail = tmp;
            cur = cur/10;
            newl1 = newl1->next;
            newl2 = newl2->next;
        }
        while (newl1){
            cur = cur + newl1->val;
            ListNode *tmp = new ListNode(cur%10);
            tail ->next = tmp;
            tail = tmp;
            cur = cur/10;
            newl1 = newl1->next;
        }
        while (newl2){
            cur = cur + newl2->val;
            ListNode *tmp = new ListNode(cur%10);
            tail ->next = tmp;
            tail = tmp;
            cur = cur/10;
            newl2 = newl2->next;
        }
        while (cur){
            ListNode *tmp = new ListNode(cur%10);
            tail ->next = tmp;
            tail = tmp;
            cur = cur/10;
        }
        return revese(head->next);
    }
};

8、回文链表

234. Palindrome Linked List(Easy)
Given a singly linked list, determine if it is a palindrome.

Example 1:

Input: 1->2
Output: false

Example 2:

Input: 1->2->2->1
Output: true

Follow up:

Could you do it in O(n) time and O(1) space?

问题分析
将链表的前一半反转,判断前一半与后一半是否相等,如:
1 -> 2 -> 2 -> 1 -> NULL 拆分为 NULL <- 1 <- 2 与 2 -> 1 -> NULL
1 -> 2 -> 1 -> NULL 拆分为 NULL <- 1 与 1 -> NULL

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        int len=0;
        ListNode*fast=head;
        while(fast!=NULL)
        {
            len++;
            fast=fast->next;
        }
        if(len<2)
            return true;
        fast=head;
        ListNode*slow=NULL;
        for(int i=1;i<=len/2;i++)//前一半反转
        {
            ListNode*tmp=fast->next;
            fast->next=slow;
            slow=fast;
            fast=tmp;
        }
        if(len%2)//如果链表个数为偶数,中间一个数不比较
            fast=fast->next;
        while(slow!=NULL&&fast!=NULL)
        {
            if(fast->val!=slow->val)
                return false;
            fast= fast->next;
            slow=slow->next;
        }
        return true;
    }
};

9、分隔链表

725. Split Linked List in Parts(Medium)
将一个链表按顺序拆解为几部分,使得每部分大小尽可能相等,长度之差不能超过1,并且较长的链表在前面,短的链表在后面。
Example 1:

Input:
root = [1, 2, 3], k = 5
Output: [[1],[2],[3],[],[]]

Example 2:

Input:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]

解题思路:根据总长度和分成多少段,可以求出短链表的长度(长度除以段数),长链表的个数(长度处于段数,取余),将原链表直接分割。这里需要注意,可能较长链表分割完之后,链表已经没有节点,短链表长度为0,直接返回即可。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<ListNode*> splitListToParts(ListNode* root, int k) {
        ListNode *pos = root;
        int n = 0;
        while(pos){
            n++;
            pos = pos->next;
        }
        int divisor = n/k;				//总长度除以看段,结果为较短链表的长度
        int remainder = n%k;			//余数为较长链表的个数
        vector<ListNode *>res(k,NULL);
        int i = 0;
        pos = root;
        for (; i < remainder; i++){
            res[i] = pos;
            for(int j = 0; j < divisor; j++)
                pos = pos->next;
            ListNode *tmp = pos;
            pos = pos->next;
            tmp->next = NULL;
        }
        if(pos == NULL)					//较短链表长度可能为0,链表节点已经分配完毕
            return res;
        for (; i < k; i++){
            res[i] = pos;
            for(int j = 0; j < divisor-1; j++)
                pos = pos->next;
            ListNode *tmp = pos;
            pos = pos->next;
            tmp->next = NULL;
        }
        return res;
    }
};

时间复杂度:O(N + k),其中N是总节点数, 如果k很大,需要创建很多空链表。
空间复杂度:O(k)

10、链表元素按奇偶聚集

328. Odd Even Linked List(Medium)
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes.
You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity.

Example 1:

Input: 1->2->3->4->5->NULL
Output: 1->3->5->2->4->NULL

Example 2:

Input: 2->1->3->5->6->4->7->NULL
Output: 2->3->6->7->1->5->4->NULL

给一个链表,将奇数下表的元素连成链表,后面连接偶数下表的元素组成的链表。
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if(head ==NULL || head->next == NULL)
            return head;
        ListNode *odd = head, *even = head->next;
        ListNode *evenhead = even;
        while(odd->next && even->next){
            odd->next = even->next;
            odd = odd->next;                
            even->next = odd->next;
            even = even->next;
        }
        odd->next = evenhead;
        return head;
    }
};

11、分区链表

86. Partition List(Medium)
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.
Example:

Input: head = 1->4->3->2->5->2, x = 3
Output: 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 || head->next == NULL) 	//为空或只有一个元素
            return head;
        int count = 0;								//大于等于x的元素个数
        ListNode* p = head;
        ListNode* tail = head;
        while(p != NULL){
            if (p->val >= x)
                count++;
            tail = p;
            p = p->next;
        }
        ListNode* newhead = new ListNode(x-1);	//创建一个小于x的元素,放链表头部,将链表原来第一元素和后面的一样处理
        newhead->next = head;
        ListNode* pre = newhead;
        p = head;
        while (count > 0){
            if (p->val >= x){					//元素大于x,移动到链表尾部
                count--;
                ListNode* tmp = p->next;
                if (tmp == NULL)				//已经在链表尾部了,不用移动了
                    continue;
                pre->next = tmp;
                tail->next = p;
                p->next = NULL;
                tail = p;
                p = tmp;
            }
            else{								//不在链表尾部,指针向前移动
                pre = p;
                p = p->next;
            }
        }
        return newhead->next;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值