你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:
val
和next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。如果是双向链表,则还需要属性
prev
以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。实现
MyLinkedList
类:
MyLinkedList()
初始化MyLinkedList
对象。int get(int index)
获取链表中下标为index
的节点的值。如果下标无效,则返回-1
。void addAtHead(int val)
将一个值为val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为val
的节点插入到链表中下标为index
的节点之前。如果index
等于链表的长度,那么该节点会被追加到链表的末尾。如果index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为index
的节点。示例:
输入 ["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"] [[], [1], [3], [1, 2], [1], [1], [1]] 输出 [null, null, null, null, 2, null, 3] 解释 MyLinkedList myLinkedList = new MyLinkedList(); myLinkedList.addAtHead(1); myLinkedList.addAtTail(3); myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3 myLinkedList.get(1); // 返回 2 myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3 myLinkedList.get(1); // 返回 3提示:
0 <= index, val <= 1000
- 请不要使用内置的 LinkedList 库。
- 调用
get
、addAtHead
、addAtTail
、addAtIndex
和deleteAtIndex
的次数不超过2000
。
思路:使用listnode实现这个链表类,记得addindex时,边界情况可以使用addhead和addtail节省很多操作
class MyLinkedList {
ListNode* head;
ListNode* tail;
int _size;
public:
MyLinkedList() {
head = tail = nullptr;
_size = 0;
}
int get(int index) {
if (index > _size) {
return -1;
}
auto node = head;
while (--index > -1 && node) {
node = node->next;
}
return node ? node->val : -1;
}
void addAtHead(int val) {
if (head == nullptr) {
head = new ListNode(val);
head->next = nullptr;
tail = head;
++_size;
return;
}
auto node = new ListNode(val);
node->next = head;
head = node;
++_size;
}
void addAtTail(int val) {
if (head == nullptr) {
addAtHead(val);
return;
}
auto node = new ListNode(val);
tail->next = node;
node->next = nullptr;
tail = node;
++_size;
}
void addAtIndex(int index, int val) {
if (index > _size) {
return;
} else if (index == 0) {
addAtHead(val);
return;
} else if (index == _size) {
addAtTail(val);
return;
}
auto pre = new ListNode(-1);
pre->next = head;
auto temp = pre;
while (--index > -1 && temp) {
temp = temp->next;
}
auto next = temp->next;
temp->next = new ListNode(val);
temp->next->next = next;
head = pre->next;
++_size;
}
void deleteAtIndex(int index) {
if (index >= _size) {
return;
}
auto pre = new ListNode(-1);
pre->next = head;
auto temp = pre;
while (--index > -1 && temp) {
temp = temp->next;
}
if (_size == 1) {
head = tail = nullptr;
--_size;
return;
}
auto next = temp->next->next;
temp->next = next;
if (!next) {
tail = temp;
}
head = pre->next;
--_size;
}
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]示例 2:
输入:head = [], val = 1 输出:[]示例 3:
输入:head = [7,7,7,7], val = 7 输出:[]提示:
- 列表中的节点数目在范围
[0, 104]
内1 <= Node.val <= 50
0 <= val <= 50
思路:使用一个前置指针即可解决边界问题
迭代方式实现并不难,难的是如何递归实现。
基本链表类的递归都可以用以下模板:
if(!head || !head->next) {
return head
}
head->next = circle(head->next);
if(xxxx) {
.....
}
return head;
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// if(!head) {
// return head;
// }
// auto pre = new ListNode(-1);
// pre->next = head;
// auto node = pre;
// while(node && node->next) {
// auto next = node->next;
// if(next->val == val) {
// auto tail = next->next;
// node->next = tail;
// } else {
// node = node->next;
// }
// }
// return pre->next;
if(!head) {
return head;
}
head->next = removeElements(head->next, val);
return head->val == val ? head->next : head;
}
};
给你一个链表,删除链表的倒数第
n
个结点,并且返回链表的头结点。示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]示例 2:
输入:head = [1], n = 1 输出:[]示例 3:
输入:head = [1,2], n = 1 输出:[1]提示:
- 链表中结点的数目为
sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
进阶:你能尝试使用一趟扫描实现吗?
思路:快慢指针,快指针走到末尾,说明慢指针就走到了要删除的节点
需要注意的是边界条件的判断
想一下递归怎么实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
int count = 0;
ListNode* removeNthFromEnd(ListNode* head, int n) {
// if(!head) {
// return head;
// }
// ListNode *pre = new ListNode(-1);
// pre->next = head;
// auto first = pre;
// auto second = pre;
// while(n--) {
// second = second->next;
// }
// while(second->next) {
// first = first->next;
// second = second->next;
// }
// if(first && first->next) {
// auto next = first->next->next;
// first->next = next;
// }
// return pre->next;
if(!head) {
return head;
}
if(n == 0) {
return head->next;
}
head->next = removeNthFromEnd(head->next, n);
++count;
return n == count ? head->next : head;
}
};
给定一个已排序的链表的头
head
, 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。示例 1:
输入:head = [1,1,2] 输出:[1,2]示例 2:
输入:head = [1,1,2,3,3] 输出:[1,2,3]提示:
- 链表中节点数目在范围
[0, 300]
内-100 <= Node.val <= 100
- 题目数据保证链表已经按升序 排列
思路:判断下一节点值是否和当前节点值一样,决定是next还是next->next
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(!head || !head->next) {
return head;
}
// auto pre = head;
// while(head) {
// if(head->next && head->val == head->next->val) {
// auto next = head->next->next;
// head->next = next;
// } else {
// head = head->next;
// }
// }
// return pre;
head->next = deleteDuplicates(head->next);
if(head->val == head->next->val) {
return head->next;
}
return head;
}
};
给定一个已排序的链表的头
head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。示例 1:
输入:head = [1,2,3,3,4,4,5] 输出:[1,2,5]示例 2:
输入:head = [1,1,1,2,3] 输出:[2,3]提示:
- 链表中节点数目在范围
[0, 300]
内-100 <= Node.val <= 100
- 题目数据保证链表已经按升序 排列
思路:这题比上一题难得是,删除所有重复节点
所以在if满足条件后,next多走一步就好
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (!head || head->next == nullptr) {
return head;
}
// auto pre = new ListNode(-101);
// pre->next = head;
// auto first = pre;
// auto second = head;
// while(first && second) {
// if(second->next && second->next->val == second->val) {
// while (second && second->next && second->next->val ==
// second->val) {
// auto next = second->next;
// second->next = next->next;
// }
// if(!second) {
// break;
// }
// auto next = second->next;
// second = next;
// first->next = second;
// } else {
// first = first->next;
// second = second->next;
// }
// }
// return pre->next;
if (head->next && head->val == head->next->val) {
while (head->next && head->val == head->next->val) {
head = head->next;
}
return deleteDuplicates(head->next);
} else {
head->next =deleteDuplicates(head->next);
return head;
}
}
};