206. 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 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) {
ListNode *new_head = NULL;
while(head)
{
ListNode *next = head->next; head->next = new_head; new_head=head; head=next; } return new_head; } };
92. 反转链表 II
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/** * 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) { int change_len = n - m + 1;//要逆置链表数 ListNode *pre_head = NULL;//开始逆置等等链表的前驱 ListNode *result = head;//最终转换后链表的头结点 while(head && --m) { pre_head = head;//记录head前驱 head = head->next; } ListNode *modify_list_tail = head; ListNode *new_head = NULL; while(head && change_len)//逆置change_len个节点 { ListNode *next = head->next; head->next = new_head; new_head = head; head = next; change_len--;//完成每一个节点逆置后change_len--; } modify_list_tail->next = head;//连接逆置后的链表尾部与逆置段的后一个节点 if(pre_head)//如果pre不是NULL,说明不是从第一个节点开始的 M > 1 { pre_head->next = new_head;//将逆置链表的开始节点与前驱相连 } else { result = new_head;//如果是空说明从第一个节点开始逆置,结果就是头节点 } return result; } };
160. 相交链表
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
先求得A和B链表的长度,让指针走到两个链表一样长度的地方。
之后两个链表一起前进如果两个指针指向相同则说明有交点。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: int get_list_length(ListNode*head) { int len = 0; while(head) { len++; head = head ->next; } return len; } ListNode * forward_long_list(int long_len, int short_len, ListNode* head) { int delta = long_len - short_len; while(head && delta) { head = head->next;//将指针移动到多出节点个数后面的位置 delta --; } return head; } ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { int list_A_len = get_list_length(headA); int list_B_len = get_list_length(headB); if(list_A_len > list_B_len) { headA = forward_long_list(list_A_len,list_B_len,headA); } else { headB = forward_long_list(list_B_len,list_A_len,headB); } while(headA && headB) { if(headA == headB) { return headA; } headA = headA->next; headB = headB->next; } return NULL; } };
141. 环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:利用快慢指针的方法来解决。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: bool hasCycle(ListNode *head) { ListNode *slow = head; if(slow == NULL) return false; ListNode *fast = head->next; while(fast && slow && fast->next) { if(fast == slow) { return true; } slow = slow->next; fast = fast->next->next; } return false; } };
142. 环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
(图略)
解题思路:首先找到一个环内的节点表明链表内确实有环,之后让链表内的相遇节点和链表外的头结点一起向前移动,这样相遇的节点就是链表的环开始的地方的节点
class Solution { public: ListNode *detectCycle(ListNode *head) { ListNode *fast = head; ListNode *slow = head; ListNode *meet = nullptr; while (fast) { slow = slow->next; fast = fast->next; if(!fast) { return nullptr; } fast = fast->next; if(fast == slow) { meet = slow; break; } } if(meet == nullptr) { return nullptr; } ListNode *start = head; while(start && meet) { if(start == meet) { return start; } start = start->next; meet = meet->next; } return NULL; } };
86. 分隔链表
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:建立两个临时链表morehead和lesshead 使用尾插法 遍历所给的head链表 把小于的插入lesshead把大于等于的插入到morehead里。这样就可以得出符合条件的两个链表 最后把morehead插入lesshead的尾部就可以了。返回lesshead头的下一个节点。
/** * 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) { ListNode less_head(0); ListNode more_head(0); ListNode *less_ptr = &less_head; ListNode *more_ptr = &more_head; while(head) { if(head->val < x) { less_ptr->next = head; less_ptr = less_ptr->next; } else { more_ptr->next = head; more_ptr = more_ptr->next; } head = head->next; } less_ptr->next = more_head.next; more_ptr->next = nullptr; return less_head.next; } };
在下一个题开始之前先复习一下stl中的映射使用方法:
#include#include #include #include #include
138. 复制带随机指针的链表
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
提示:
-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
第一步:
遍历链表 每读到一个节点,就创建一个心的节点 把它放入vector中
把当前遍历的链表地址和对应遍历的链表数放入map中
第二步:
再次遍历链表,首先根据遍历的进度把新链表(也就是vector里面的链表)首尾相接
再根据遍历原链表 得到 对应当前 str所指向的 random指针域里存放(指向)的地址 所对应的map映射(也就是第几个)
再把新链表(vector中存放的)中的random指向对应(第几个)vector的地址。
这样就可以实现新链表的random链接了。
class Node { public: int val; Node* next; Node* random; Node(int _val) { val = _val; next = NULL; random = NULL; } }; class Solution { public: Node* copyRandomList(Node* head) { mapint> node_map;//地址到节点位置map vector node_vec; Node *ptr = head;//使用vector根据存储节点位置访问地址 int i = 0; while(ptr)//将新链表节点push到node_vec中 { node_vec.push_back(new Node(ptr->val)); node_map[ptr] = i; ptr = ptr->next; i++;//遍历原始链表 } node_vec.push_back(0); ptr = head; i=0;//再次遍历原始链表,连接新的链表的next指针,random指针 while(ptr) { node_vec[i]->next = node_vec[i+1];//连接新链表的next if(ptr->random)//当random指针不为空的时候 { int id = node_map[ptr->random];//根据node_map确认 node_vec[i]->random = node_vec[id];//原链表random指向的位置id } ptr = ptr->next;//连接新链表random指针 i++; } return node_vec[0]; } };
21. 合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-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 head(0); ListNode *ptr = &head; ListNode *p1 = l1, *p2 = l2; while(p1 && p2) { if(p1->val < p2->val) { ptr->next = p1; p1 = p1->next; } else { ptr->next = p2; p2 = p2->next; } ptr = ptr->next; } if(p1 == NULL && p2 != NULL) { ptr->next = p2; } else if(p2 == NULL && p1 != NULL) { ptr->next = p1; } else { ptr->next = NULL; } return head.next; } };
最后来一个升级版的练习
这里采用了的是归并思想,把N条链表进行分治处理最后归并也可以高效率的解决问题~
23. 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-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 head(0); ListNode *ptr = &head; ListNode *p1 = l1, *p2 = l2; while(p1 && p2) { if(p1->val < p2->val) { ptr->next = p1; p1 = p1->next; } else { ptr->next = p2; p2 = p2->next; } ptr = ptr->next; } if(p1 == NULL && p2 != NULL) { ptr->next = p2; } else if(p2 == NULL && p1 != NULL) { ptr->next = p1; } else { ptr->next = NULL; } return head.next; } ListNode* mergeKLists(vector& 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; vector sub1_lists; vector 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); } };