一、参考资料
链表理论基础
文章链接:https://programmercarl.com/%E9%93%BE%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
移除链表元素
题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
设计链表
题目链接/文章讲解/视频讲解:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html
反转链表
题目链接/文章讲解/视频讲解:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
二、LeetCode203.移除链表元素
我的代码
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> res;
for (int i = 0; i < nums.size(); i++){
nums[i] = nums[i] * nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
接下来学习一下双指针的代码实现:
双指针实现
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
// 这里定义一个结果集,长度为原数组的大小
vector<int> res(nums.size(), 0);
// 定义首尾指针
int firstp = 0;
int lastp = nums.size() - 1;
int k = lastp; // k表示结果集的指针,从后向前写入vector
while (firstp <= lastp){
if (nums[firstp] * nums[firstp] < nums[lastp] * nums[lastp]){
res[k--] = nums[lastp] * nums[lastp];
lastp--;
}
else{
res[k--] = nums[firstp] * nums[firstp];
firstp++;
}
}
return res;
}
};
三、LeetCode707.设计链表
class MyLinkedList {
public:
// 定义链表节点结构体——单链表
struct LinkedNode {
int val; // 节点上存储的元素
LinkedNode *next; // 指向下一个节点的指针
LinkedNode(int x) : val(x), next(NULL){} //节点的构造函数
};
// 初始化链表
MyLinkedList() {
_dummyHead = new LinkedNode(0); // 定义虚拟头结点,不是真正的链表头结点
_size = 0;
}
// 获取第index个节点的数值,如果index是非法数值直接返回-1
int get(int index) {
if (index > (_size - 1) || index < 0) {
return -1;
}
LinkedNode *cur = _dummyHead->next;
// 如果--index就会陷入死循环
while (index--) {
cur = cur->next;
}
return cur->val;
}
// 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
void addAtHead(int val) {
LinkedNode *newNode = new LinkedNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
// 在链表最后面添加一个节点
void addAtTail(int val) {
LinkedNode *newNode = new LinkedNode(val);
LinkedNode *cur = _dummyHead;
while(cur->next != NULL) {
cur = cur->next;
}
cur->next = newNode;
_size++;
}
// 添加节点
void addAtIndex(int index, int val) {
if (index > _size) return;
if (index < 0) index = 0;
LinkedNode *newNode = new LinkedNode(val);
LinkedNode *cur = _dummyHead;
while (index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
// 删除节点
void deleteAtIndex(int index) {
if (index >= _size || index < 0) {
return;
}
LinkedNode *cur = _dummyHead;
while (index--) {
cur = cur->next;
}
LinkedNode *tmp = cur->next;
cur->next = tmp->next; // cur->next = cur->next->next;
delete tmp;
_size--;
}
private:
int _size;
LinkedNode* _dummyHead;
};
// // 打印链表
// void printLinkedList() {
// LinkedNode* cur = _dummyHead;
// while (cur->next != nullptr) {
// cout << cur->next->val << " ";
// cur = cur->next;
// }
// cout << endl;
// }
/**
* 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);
*/
四、LeetCode206.反转链表
这个题以前是做过的,链表用的不熟练还是不能很快写出来(这篇先写了双指针法,递归法下次补上)
双指针法实现反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* temp; // 保存cur的下一个节点
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur->next = pre; // 翻转操作
// 更新pre 和 cur指针
pre = cur;
cur = temp;
}
return pre;
}
};
递归法(卡哥带注释版本)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
// 边缘条件判断
if(head == NULL) return NULL;
if (head->next == NULL) return head;
// 递归调用,翻转第二个节点开始往后的链表
ListNode *last = reverseList(head->next);
// 翻转头节点与第二个节点的指向
head->next->next = head;
// 此时的 head 节点为尾节点,next 需要指向 NULL
head->next = NULL;
return last;
}
};
Day03总结:
指针操作的原理还是可以理解的,但是写代码就不太顺手
看代码能看懂,但自己写的时候容易遗忘,或者思路容易不清楚
规范化操作很重要,包括对节点空间的释放(Java和python不需要考虑)以及结构体的初始化等。