<LeetCode>
链表逆序
206. 反转链表 反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->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
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
int change_len = n - m +1;//计算需要逆置节点个数
ListNode *pre_head = NULL; // 初始化开始逆置节点的前驱
ListNode *result = head; //最终转化后的链表头节点,非特殊情况即为head
while(head && --m ){// 将head向前移动m-1位置
pre_head = head;
head = head->next;
}
ListNode * modify_list_tail = head;//将modify_list_tail 指向当前的head,即逆置后的链表尾
ListNode * new_head = NULL;
while(head && change_len){
ListNode * next = head->next;
head->next = new_head;
new_head = head;
head = next;
change_len -- ;
}
modify_list_tail->next = head;
if(pre_head){
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) 内存。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
set<ListNode *> test_set;
ListNode* head=headA;
while(headA)
{
test_set.insert(headA);
headA=headA->next;
}
while(headB)
{
if(test_set.find(headB)!=test_set.end())
{
return headB;
}
headB=headB->next;
}
return NULL;
}
};
class Solution {
public:
int get_list_len(ListNode *head)
{
int len=0;
while(head)
{
++len;
head=head->next;
}
return len;
}
ListNode *forward_long_list(ListNode *head,int long_len,
int short_len)
{
int offset=long_len-short_len;
while(head&&offset)
{
head=head->next;
--offset;
}
return head;
}
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int list_A_len=get_list_len(headA);
int list_B_len=get_list_len(headB);
if(list_A_len>list_B_len)
{
headA=forward_long_list(headA,list_A_len,
list_B_len);
}
else{
headB=forward_long_list(headB,list_B_len,
list_A_len);
}
while(headA&&headB)
{
if(headA==headB)
{
return headA;
}
headA=headA->next;
headB=headB->next;
}
return NULL;
}
};
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
解释:链表中没有环。
思路一:同上题目,使用set<>
思路二:
思路:设链表结点总数为m+n,其中n为链表头结点到环开始的结点的个数,m为环的结点个数,设快慢指针在第n+x(x<m)结点处相遇:
快指针:n/2+x/2+m/2 ,其中m/2时快指针多跑的一圈
慢指针:n+x
n+x=n/2+x/2+m/2
得出n=m-x,则相遇结点再走n个结点就到环开始的结点,开年表头结点走n个结点就到环开始的结点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *slow=head;
ListNode *fast=head;
ListNode *meet=NULL;
while(fast)
{
slow=slow->next;
fast=fast->next;
if(!fast)
{
return NULL;
}
fast=fast->next;
if(fast==slow)
{
meet=fast;
break;
}
}
if(meet==NULL)
{
return NULL;
}
while(head&&meet)
{
if(head==meet)
{
return head;
}
head=head->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
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=NULL;
return less_head.next;
}
};
138. 复制带随机指针的链表
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
输入:
{"$id":“1”,“next”:{"$id":“2”,“next”:null,“random”:{"$ref":“2”},“val”:2},“random”:{"$ref":“2”},“val”:1}
解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
提示:
你必须返回给定头的拷贝作为对克隆列表的引用。
class Solution {
public:
Node* copyRandomList(Node* head) {
std::map<Node *,int> node_map;
std::vector<Node *> node_vec;
Node *ptr = head;
int i = 0;
while(ptr)
{
node_vec.push_back(new Node(ptr->val,NULL,NULL));
node_map[ptr] = i;
ptr = ptr->next;
i++;
}
node_vec.push_back(0);
ptr = head;
i = 0;
while(ptr)
{
node_vec[i]->next = node_vec[i+1];
if(ptr->random)
{
int id = node_map[ptr->random];
node_vec[i]->random = node_vec[id];
}
ptr = ptr->next;
i++;
}
return node_vec[0];
}
};
21. 合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode temp_head(0);
ListNode *pre=&temp_head;
while(l1&&l2)
{
if(l1->val<l2->val)
{
pre->next=l1;
l1=l1->next;
}else{
pre->next=l2;
l2=l2->next;
}
pre=pre->next;
}
pre->next=l1==NULL?l2:l1;
return temp_head.next;
}
};
23. 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode temp_head(0);
ListNode *pre=&temp_head;
while(l1&&l2)
{
if(l1->val<l2->val)
{
pre->next=l1;
l1=l1->next;
}else{
pre->next=l2;
l2=l2->next;
}
pre=pre->next;
}
pre->next=l1==NULL?l2:l1;
return temp_head.next;
}
ListNode* mergeKLists(vector<ListNode*>& 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<ListNode *> sub1_lists;
vector<ListNode *> 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);
}
};