来水一波吧,这两天有事儿都没写这一部分的,有点难受。
前两题都很基本,第三题还好啦。
这篇主要是关于链表的,所以我先放一个链表的基础篇,今天整理的。
接下来如正题:
第一题 删除指定节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 – head = [4,5,1,9]
示例 1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
不要从你的函数中返回任何结果。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第二题 删除倒数第n个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第三题 翻转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的题解(1)
滥竽充数一下
void deleteNode(ListNode* node) {
// write your code here
if(node==NULL) return;
if(node->next==NULL)
{
node=NULL;
return;
}
node->val=node->next->val;
node->next=node->next->next;
}
我的题解(2)
这题难度居然能排在中等。。。
还是滥竽充数一下。
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(!head) return NULL;
ListNode* new_head = new ListNode(0);
new_head->next = head;
ListNode* slow = new_head, *fast = new_head;
for(int i = 0;i<n;++i){ //fast先移动n
fast = fast->next;
}
if(!fast) return new_head->next;
while(fast->next){ //一起移动
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return new_head->next;
}
我的题解(3)
这题有点意思,重点讲这题吧
一开始我的想法是这样的:先遍历一遍,将链表中的值都取出来,然后逆向插回去,不过这样要遍历两遍,于是我就想一遍实现。
我的想法是这样的:头向后遍历,每次将当前遍历到的尾部节点提取出来,放到最前面,实现逆转乾坤。
但是,想法总是好的。
先看我的第一个实验:
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
}; //通用
//ListNode* reverseList(ListNode* head)
//{
// ListNode* node_temp;
// ListNode* new_head;
//
// node_temp = head;
// //遍历一个节点,就把它拿下来放到头去
// while (head->next != NULL)
// {
// //先考虑只又两个节点的情况
// head = head->next;
// new_head = head;
// new_head->next = node_temp;
// node_temp = new_head;
// }
// return new_head;
//}
我也不多说,为什么失败,要是一眼看出来的话,容我呼你一声大神。反正这失败我是无语了。
再看第二次,算了我还是说一下上面那个。
我想原地逆置,然后一不小心,成环了。。。。。。。
于是我就换了个思路,用两条链表,一个原链表,一个链栈。
然而,想法还是好的。
//ListNode* reverseList(ListNode* head)
//{
// ListNode* node_temp = new ListNode(NULL);
// ListNode* new_head = new ListNode(NULL); //链栈的头
//
// //遍历一个节点,就把它拿下来放到头去
// while (head != NULL)
// {
// node_temp = head; //先将节点取出
// //先考虑只又两个节点的情况
// head = head->next; //这个不放这里又成环了
//
// node_temp->next = new_head;
// new_head= node_temp;
// }
// return new_head;
//}
哎,要是一眼没看出来哪里出问题了,那咱俩水平半斤八两。
这时候,我的好兄弟一直喊我用头插法,我不以为然,让他给我发过来瞅瞅。
在我看之前,我好像发现了什么。于是我就把上面的代码稍微调了一下。。。
成功了。。。
ListNode* reverseList(ListNode* head)
{
ListNode* node_temp = NULL; //这里设为NULL
ListNode* new_head = NULL; //链栈的头
//遍历一个节点,就把它拿下来放到头去
while (head != NULL)
{
node_temp = head; //先将节点取出
//先考虑只又两个节点的情况
head = head->next; //这个不放这里又成环了
node_temp->next = new_head;
new_head= node_temp;
}
return new_head;
}
ListNode* reverseList(ListNode* head)
{
ListNode* node_temp = NULL; //这里设为NULL
ListNode* new_head = NULL; //链栈的头
//遍历一个节点,就把它拿下来放到头去
while (head != NULL)
{
node_temp = head; //先将节点取出
//先考虑只又两个节点的情况
head = head->next; //这个不放这里又成环了
node_temp->next = new_head;
new_head= node_temp;
}
return new_head;
}
成功就算了,我回头一看他的“头插法”,我都懵了,怎么一模一样。。。。。
官方题解(3)
假设存在链表 1 → 2 → 3 → Ø,我们想要把它改成 Ø ← 1 ← 2 ← 3。
在遍历列表时,将当前节点的 next 指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针来存储下一个节点。不要忘记在最后返回新的头引用!
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
复杂度分析
时间复杂度:O(n),假设 n 是列表的长度,时间复杂度是 O(n)。
空间复杂度:O(1)。
作者:LeetCode
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法二:递归
递归版本稍微复杂一些,其关键在于反向工作。假设列表的其余部分已经被反转,现在我该如何反转它前面的部分?
假设列表为:
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
复杂度分析
时间复杂度:O(n)O(n),假设 nn 是列表的长度,那么时间复杂度为 O(n)O(n)。
空间复杂度:O(n)O(n),由于使用递归,将会使用隐式栈空间。递归深度可能会达到 nn 层。
作者:LeetCode
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。