本文内容是基于小象学院——林沐 《面试算法 LeetCode 刷题班》,后期仍将对相关内容进行不定期更新!
问题描述:
已知链表头节点指针head,将链表逆序。
提交代码:
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;
}
};
问题描述:
已知链表头节点指针head,将链表从位置 m 到 n 逆序。
提交代码:
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->next;
}
ListNode *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;
}
};
问题描述:
已知链表A 的头节点指针 headA,链表B 的头节点 headB, 两个链表相交,求两个链表交点对应的节点。
要求:
1.如果两个链表没有交点,则返回NULL
2.在求交点过程中,不可破坏链表的结构或者修改链表的数据域
3.确保链表A和B都没有环
4*.实现算法时间复杂度O(n),空间复杂度O(1)
算法思路1:用标准库 set 求交集
1.遍历链表A,将A中节点对应的指针(地址),插入 set
2.遍历链表B,将B中节点依次在 set 中查找,发现即为两个链表交点,未发现则返回NULL
代码实现:
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
set tmp_set;
while (headA)
{
tmp_set.insert(headA);
headA = headA->next;
}
while (headB)
{
if (tmp_set.find(headB) != tmp_set.end()) {
return headB;
}
else
{
headB = headB->next;
}
}
return NULL;
}
};
思路2: 空间复杂度O(1)
1.计算headA链表长度,计算链表B的链表长度,从而得出较长的链表多出的长度
2.将较长的链表的指针移动到和较短链表指针对齐的位置
3.headA 与 headB 同时移动,当两个指针指向同一个节点时,即找到了
代码实现:
int get_len(ListNode *head) {
int len = 0;
while (head)
{
len++;
head = head->next;
}
return len;
}
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int headA_len = get_len(headA);
int headB_len = get_len(headB);
if (headA_len > headB_len)
{
int dis = headA_len - headB_len + 1;
while (headA && -- dis)
{
headA = headA->next;
}
}
else if(headA_len < headB_len)
{
int dis = headB_len - headA_len + 1;
while (headB && --dis)
{
headB = headB->next;
}
}
while (headA && headB)
{
if (headA == headB) {
return headA;
}
headA = headA->next;
headB = headB->next;
}
return NULL;
}
};
问题描述:
141.已知链表中可能存在环,若有则返回真,否则返回假
142.已知链表中可能存在环,若有则返回环起始节点,否则返回NULL
思路1:用 set 求环起始节点
提交代码:141
class Solution {
public:
bool hasCycle(ListNode *head) {
set tmp_set;
while (head)
{
if (tmp_set.find(head) == tmp_set.end()) {
tmp_set.insert(head);
head = head->next;
}
else
{
return true;
}
}
return false;
}
};
提交代码:142
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
set tmp_set;
while (head)
{
if (tmp_set.find(head) == tmp_set.end()) {
tmp_set.insert(head);
head = head->next;
}
else
{
return head;
}
}
return NULL;
}
};
思路2:快慢指针
首先设两个指针,一个slow指针每次前进1次,一个 fast 指针每次前进2次,然后当他们他们首次相遇时,从相遇点 meet 出发,和从 head 出发,速度相同,相遇时即为环的起点
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)
{
break;
}
fast = fast->next;
if (fast == slow)
{
meet = fast;
break;
}
}
if (meet == NULL)
{
return NULL;
}
while (head && meet)
{
if (head == meet) {
return meet;
}
head = head->next;
meet = meet->next;
}
return NULL;
}
};
问题描述:
已知链表头指针head与数值x,将所有小于x的节点放在大于或等于x的节点前,且保持这些节点的原来的相对位置
提交代码:
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 = head;
}
else
{
more_ptr->next = head;
more_ptr = head;
}
head = head->next;
}
less_ptr->next = more_head.next;
more_ptr->next = NULL;
return less_head.next;
}
};
问题描述:
已知两个已排序链表头节点指针l1 与 l2,将这两个链表合并,合并后仍为有序的,返回合并后的头节点。
思路:
比较 l1 与 l2 指向的节点,将较小的节点插入到 pre 指针后,并向前移动较小的节点对应的指针。
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode tmp_node(0);
ListNode *pre_node = &tmp_node;
while (l1 && l2)
{
if (l1->val < l2->val)
{
pre_node->next = l1;
l1 = l1->next;
}
else {
pre_node->next = l2;
l2 = l2->next;
}
pre_node = pre_node->next;
}
if (l1)
{
pre_node->next = l1;
}
if (l2)
{
pre_node->next = l2;
}
return tmp_node.next;
}
};
问题描述:
已知K个已排序链表头节点指针,将这k个链表合并,合并后仍为有序的,返回合并后的头节点。
思路1:
按照上述方式,将k个链表按顺序合并 k-1 次, 可以通过但是效率很慢。
提交代码1:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode tmp_node(0);
ListNode *pre_node = &tmp_node;
while (l1 && l2)
{
if (l1->val < l2->val)
{
pre_node->next = l1;
l1 = l1->next;
}
else {
pre_node->next = l2;
l2 = l2->next;
}
pre_node = pre_node->next;
}
if (l1)
{
pre_node->next = l1;
}
if (l2)
{
pre_node->next = l2;
}
return tmp_node.next;
}
ListNode* mergeKLists(vector& lists) {
if (lists.size() == 0)
{
return NULL;
}
if (lists.size() == 1)
{
return lists[0];
}
for (int i = 0; i <= lists.size() - 2; i++)
{
lists[i + 1] = mergeTwoLists(lists[i], lists[i + 1]);
}
return lists[lists.size() - 1];
}
};
思路2:
将 K*n 个节点放到 vector 中,再将vector排序,再将所有节点顺序相连。
提交代码2:**
bool cmp(const ListNode* A, const ListNode* B) {
return A->val < B->val;
}
class Solution {
public:
ListNode* mergeKLists(vector& lists) {
vector List_all;
for (int i = 0; i < lists.size() ; i++)
{
while (lists[i])
{
List_all.push_back(lists[i]);
lists[i] = lists[i]->next;
}
}
if (List_all.size() == 0)
{
return NULL;
}
sort(List_all.begin(), List_all.end(),cmp);
for (int i = 1; i < List_all.size(); i++)
{
List_all[i - 1]->next = List_all[i];
}
List_all[List_all.size() - 1]->next = NULL;
return List_all[0];
}
};
思路3:
对 k 个链进行分制,两两进行合并。
提交代码3:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode tmp_node(0);
ListNode *pre_node = &tmp_node;
while (l1 && l2)
{
if (l1->val < l2->val)
{
pre_node->next = l1;
l1 = l1->next;
}
else {
pre_node->next = l2;
l2 = l2->next;
}
pre_node = pre_node->next;
}
if (l1)
{
pre_node->next = l1;
}
if (l2)
{
pre_node->next = l2;
}
return tmp_node.next;
}
ListNode* mergeKLists(vector& lists) {
if (lists.size() == 0)
{
return NULL;
}
if (lists.size() == 1)
{
return lists[0];
}
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);
}
};
问题描述:
已知一个复杂的链表,节点中有一个指向本链表任意某个节点的随机指针(也可以为空),求这个链表的深度拷贝。
思路:节点地址与节点序号对应
提交代码:
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
map node_map;
vector node_vec;
RandomListNode *ptr = head;
int i = 0;
while (ptr)
{
node_vec.push_back(new RandomListNode(ptr->label));
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];
}
};