LeetCode刷题day25

简介: LeetCode刷题day25

203. 移除链表元素


给你一个链表的头节点 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
输出:[]


方法一:使用虚拟头结点

先为原始链表创建一个虚拟头结点,然后在下一个节点存在的情况下,判断下一个节点是否 == val,如果等于则进行删除操作.否则继续遍历.

参考代码1

//使用带虚拟头结点的方法. 
ListNode* removeElements(ListNode* l, int val) {
  ListNode* L = new ListNode(-1,l);
  ListNode* p = L,*q;//注意这里的指针定义. 
  while(p->next!=NULL){//如果当前节点的下一个节点不为空. 
    if(p->next->val==val){
      q = p->next;
      p->next = p->next->next;//指针方向进行变化. 
      delete q;//删除该节点. 
    }else{
      p = p->next;//更新p 
    } 
  } 
  p = L->next;
  delete L; 
  return p;
}

方法二:无虚拟头结点


因为头结点前面没有节点,所以如果头结点是我们的删除目标,删除的办法就和删除非头结点的不同,需要特殊处理.


所以基本思路是:


先判断头结点是否 == val,如果等于则直接指针后移,并进行删除该节点.

头结点处理完毕后,继续后序的处理,依次遍历节点,判断当前节点的下一个节点是否 == val,如果等于则进行删除下一个节点.不相等,则指针后移,继续遍历.


参考代码2

ListNode* removeElements(ListNode* l, int val) {
  //删除头结点. 
  ListNode* temp;
  while(l!=NULL&&l->val==val){
    temp = l;
    l = l->next;
    delete temp;
  } 
  if(l==NULL){//判断头结点是否为null了,如果是,则直接返回NULL. 
    return NULL;
  }
  //删除非头结点 (和第一种方法一样) 
  ListNode* cur  = l;
  while(cur->next!=NULL){
    if(cur->next->val==val){
      temp = cur->next;
      cur->next = cur->next->next;
      delete temp;
    }else{
      cur = cur->next;
    }
  } 
  return l; 
}

206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

07d3ddf7fa514d0f933a9bc89fe96ac8.jpg

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

e3919c0e2a3d4c1b8a8ef09766cd4ce7.jpg

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

方法一:双指针

基本思路:从前往后将指针的方向改变,返回最后一个节点

使用pre指向前一个节点,cur代表当前节点,从第一个节点开始进行遍历,每次让cur指向pre,之后cur继续遍历下一个节点,直至链表遍历完毕.

image.gif

参考代码1

//双指针法 
ListNode* reverseList(ListNode* head) {
  ListNode* cur = head;
  ListNode* pre = NULL;
  ListNode* temp;//用于保存当前节点的下一个节点.
  while(cur){
    temp = cur->next;
    cur->next = pre;//改变当前节点的指针方向. 
    pre = cur;//pre指针后移 
    cur = temp;//当前节点后移. 
  } 
  return pre;
}

方法二:递归1(从前往后改变指针方向)


思路和方法一基本一致,递归实际上就是自己调用自己,每次的操作一致.

  • 每次我们需要改变指针指向,需要操作两个节点,当前节点cur和上一个节点pre,所以这就是递归函数的参数.
  • 递归的结束条件就是当前节点为NULL,则不再需要改变方向了.递归结束.

参考代码2

//递归本质上就是在做相同的操作,自己不断的调用自己. 
ListNode* reverse(ListNode* pre,ListNode* cur){
  if(cur==NULL){
    return pre;
  }
  ListNode* temp = cur->next;
  cur->next = pre;
  return reverse(cur,temp);//继续递归. 
}
ListNode* reverseList(ListNode* head) {
  return reverse(NULL,head); 
} 

方法三:递归2(从后往前改变指针方向)

后期进行完善…

24. 两两交换链表中的节点


给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

b61eda832b784625bb8f7751126bd111.jpg


输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

思路分析

题目的要求是交换相邻的节点,题目也说了是这两个节点的顺序发生改变,而不是仅仅交换下值.而且如果当前节点只有一个,则肯定不需要交换啦.

两个数进行交换我们需要一个中间值.而两个节点 1, 2 进行交换涉及到当前节点 0 的指向,A,B这两个节点的指针指向.

接下来我们用图解来表示:

3df8ef70481d4f4f84dd7d89ca2389f8.jpg

根据图中,我们可以使用三个辅助变量便可完成操作.

参考代码


ListNode* swapPairs(ListNode* l) {
  ListNode* head = new ListNode(-1,l);
  ListNode* cur = head;
  ListNode* temp1,temp2,temp3;//分别存放,当前节点后面的三个节点,便于操作.
  while(cur->next!=NULL&&cur->next->next!=NULL){
    temp1 = cur->next;
    temp2 = cur->next->next;
    temp3 = cur->next->next->next;
    cur->next = temp2;//执行第一步:当前0节点指向2号节点
    temp2->next = temp1;//执行第二步:当前2节点指向1号节点
    temp1->next = temp3;//执行第三步:当前1节点指向3号节点.
    cur = cur->next->next;//cur后移两位. 
  } 
  return  head->next; 
}

19. 删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

ccc82e97c1174cfc8800343c555e24e6.jpg

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

思路分析

快慢指针


先搞一个虚拟头结点,方便我们接下来的操作.


第一步slow和fast都指向虚拟头结点.

第二步fast向前移动n+1个节点

slow和fast同时向前移动,直至fast为空,则slow对应的便是目标节点的前一个节点.

为啥fast要先移动n+1个节点呢?why?

因为这样的话,之后当fast和slow同时移动,当fast为null时,slow对应的刚好是target前一个节点. 而如果是n,则slow对应的是目标节点.


ffa2a2d67f5d4b20adec0cefc87f0d25.png

参考代码

ListNode* removeNthFromEnd(ListNode* l, int n) {
  ListNode* head = new ListNode(-1,l);
  ListNode* fast = head,*slow=  head;
  while(n--&&fast){
    fast = fast->next;
  }
  fast = fast->next;//fast再向前走一步,因为需要让slow指向删除节点的上一个节点
  while(fast){
    fast=fast->next;
    slow = slow->next;
  } 
  slow->next = slow->next->next;
  return head->next;
}
相关文章
|
6天前
|
索引
【力扣刷题】两数求和、移动零、相交链表、反转链表
【力扣刷题】两数求和、移动零、相交链表、反转链表
15 2
【力扣刷题】两数求和、移动零、相交链表、反转链表
|
6天前
|
算法
"刷题记录:哈希表+双指针 | leetcode-2465. 不同的平均值数目 "
该文段是一篇关于编程题目的解答,主要讨论如何找到数组中所有不同平均值的个数。作者首先使用排序和哈希集来解决,将数组转为列表排序后,通过双指针计算平均值并存入哈希集以去重。然后,作者发现可以优化方案,通过双指针在排序后的数组中直接计算两数之和,用哈希集记录不重复的和,从而避免实际计算平均值,提高了算法效率。最终代码展示了这两种方法。
14 0
|
6天前
|
索引
【力扣刷题】删除链表的倒数第 N 个结点、两两交换链表中的节点、随机链表的复制
【力扣刷题】删除链表的倒数第 N 个结点、两两交换链表中的节点、随机链表的复制
12 0
|
6天前
|
存储 算法 索引
【力扣刷题】只出现一次的数字、多数元素、环形链表 II、两数相加
【力扣刷题】只出现一次的数字、多数元素、环形链表 II、两数相加
16 1
|
6天前
【力扣刷题】二叉树的中序遍历、二叉树的最大深度、翻转二叉树、对称二叉树
【力扣刷题】二叉树的中序遍历、二叉树的最大深度、翻转二叉树、对称二叉树
14 0
|
6天前
|
索引
【力扣刷题】数组实现栈、后缀表达式(逆波兰表达式)求值、中缀表达式转换为后缀表达式(无括号&&有括号)
【力扣刷题】数组实现栈、后缀表达式(逆波兰表达式)求值、中缀表达式转换为后缀表达式(无括号&&有括号)
11 0
|
6天前
|
索引
【力扣刷题】回文链表、环形链表、合并两个有序链表
【力扣刷题】回文链表、环形链表、合并两个有序链表
12 0
|
9天前
|
算法 索引
力扣刷题【第一期】
这是一个关于算法的总结,包含7个不同的问题。1)爬楼梯问题,使用动态规划,通过迭代找到到达n阶楼梯的不同方法数。2)两数之和,通过双重循环找出数组中和为目标值的两个数的索引。3)移动零,使用双指针将数组中的0移到末尾。4)合并有序链表,创建新链表按升序合并两个链表。5)删除链表重复值,遍历链表删除重复元素。6)环形链表检测,使用快慢指针判断链表是否有环。7)相交链表,计算链表长度找
14 1
|
9天前
|
存储 Java
JAVA数据结构刷题 -- 力扣二叉树
JAVA数据结构刷题 -- 力扣二叉树
16 0
|
18天前
|
算法 C++
【刷题】Leetcode 1609.奇偶树
这道题是我目前做过最难的题,虽然没有一遍做出来,但是参考大佬的代码,慢慢啃的感觉的真的很好。刷题继续!!!!!!
14 0