• 算法通关村第二关-白银挑战反转链表拓展问题


    大家好我是苏麟 , 今天聊一聊链表反转拓展问题 . 

    反转链表拓展问题

    1.指定区间反转

    描述

    给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

    题目 :

    LeetCode 92.反转链表

    92. 反转链表 II
     

    牛客 BM2 链表内指定区间反转 : 

    分析 : 

    这里的处理方式也有多种,甚至给个名字都有点困难,干脆就分别叫穿针引线法和头插法吧。穿针引线本质上就是不带有节点的方式来实现反转,而头插法本质上就是带头结点的反转。

    头插法

    这个方法的缺点是:

    如果 left 和 right 的区域很大,恰好是链表的头节点和尾节点时,找到left 和 right 需要遍历一次,反转它们之间的链表还需要遍历一次,虽然总的时间复杂度为 O(N),但遍历了链表 2次,p不可以只遍历一次呢? 答案是可以的。我们依然画图进行说明,我们仍然以方法一的序列为例进行说明。

    反转的整体思想是,在需要反转的区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置。
    下面的图展示了整个流程。

    这个过程就是前面的带虚拟结点的插入操作,每走一步都要考虑各种指针怎么指,既要将结点摘下来接到对应的位置上,还要保证后续结点能够找到,请读者务必画图看一看,想一想到底该怎么调整。

    代码如下 :

    1. /**
    2. * Definition for singly-linked list.
    3. * public class ListNode {
    4. * int val;
    5. * ListNode next;
    6. * ListNode() {}
    7. * ListNode(int val) { this.val = val; }
    8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
    9. * }
    10. */
    11. class Solution {
    12. public ListNode reverseBetween(ListNode head, int left, int right) {
    13. ListNode dummyNode = new ListNode(-1);
    14. dummyNode.next = head;
    15. ListNode pre = dummyNode;
    16. for (int i = 0; i < left - 1; i++) {
    17. pre = pre.next;
    18. }
    19. ListNode cur = pre.next;
    20. ListNode next;
    21. for (int i = 0; i < right - left; i++) {
    22. next = cur.next;
    23. cur.next = next.next;
    24. next.next = pre.next;
    25. pre.next = next;
    26. }
    27. return dummyNode.next;
    28. }
    29. }

    2.单链表加一

    描述 : 

    给定一个用单链表表示的整数,然后把这个整数加一。

    题目 :

    LeetCode  66.加一 :

    66. 加一

    LeetCode 369.给单链表加一 :

     369. 给单链表加一

    牛客 NC189 给单链表加一 :

    分析 : 

    我们先看一下加法的计算过程:
    计算是从低位开始的,而链表是从高位开始的,所以要处理就必须反转过来,此时可以使用栈,也可以使用链表反转来实现。
    基于栈实现的思路不算复杂,先把题目给出的链表遍历放到栈中,然后从栈中弹出栈顶数字 digit,加的时候再考虑一下进位的情况就ok了,加完之后根据是否大于0决定视为下一次要进位 .
    
    1. import java.util.*;
    2. /*
    3. * public class ListNode {
    4. * int val;
    5. * ListNode next = null;
    6. * public ListNode(int val) {
    7. * this.val = val;
    8. * }
    9. * }
    10. */
    11. public class Solution {
    12. /**
    13. * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
    14. *
    15. *
    16. * @param head ListNode类
    17. * @return ListNode类
    18. */
    19. public ListNode plusOne (ListNode head) {
    20. // write code here
    21. /**
    22. 把数字压入栈中
    23. */
    24. Stack s = new Stack<>();
    25. while(head!=null){
    26. s.push(head.val);
    27. head = head.next;
    28. }
    29. ListNode d = new ListNode(-100);
    30. ListNode p = d;
    31. //carry代表进位
    32. int carry = 0;
    33. //x代表要加的1
    34. int x = 1;
    35. while(!s.empty() || carry == 1){
    36. int y = s.empty() ? 0 : s.pop() ;
    37. int num = carry + x + y;
    38. carry = num >= 10 ? 1 : 0;
    39. num = num >= 10 ? num-10 : num;
    40. //头插
    41. ListNode temp = new ListNode(num);
    42. temp.next = p.next;
    43. p.next = temp;
    44. x = 0;
    45. }
    46. return d.next;
    47. }
    48. }

    基于链表反转实现 如果这里不使用栈,使用链表反转来实现该怎么做呢?很显然,我们先将原始链表反转,这方面完成加1和进位等处理,完成之后再次反转。本实现作为一个作业,请读者完成。

    3.链表加法

    相加相链表是基于链表构造的一种特殊题,反转只是其中的一部分。这个题还存在进位等的问题,因此看似简单,但是手写成功并不容易。

    这道题有不同种问法 , 但都是问基础知识链表头插尾插 , 反转 ...

    描述 :

    给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

    请你将两个数相加,并以相同形式返回一个表示和的链表。

    题目 : 

    LeetCode 2.两数加法 :

    2. 两数相加

     解析 : 

    思路是将两个结果分别计算。之后对计算结果取模,模数保存到新的链表中,进位保存到下一轮。

    尾插就好了 .

    使用链表法

    1. /**
    2. * Definition for singly-linked list.
    3. * public class ListNode {
    4. * int val;
    5. * ListNode next;
    6. * ListNode() {}
    7. * ListNode(int val) { this.val = val; }
    8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
    9. * }
    10. */
    11. class Solution {
    12. public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    13. //虚拟节点
    14. ListNode newNode = new ListNode(-100);
    15. ListNode p = newNode;
    16. //代表进位
    17. int carry = 0;
    18. while(l1 != null || l2 != null || carry == 1){
    19. int x = 0;
    20. int y = 0;
    21. if(l1 != null){
    22. x = l1.val;
    23. l1 = l1.next;
    24. }
    25. if(l2 != null){
    26. y = l2.val;
    27. l2 = l2.next;
    28. }
    29. int sum = x + y + carry;
    30. carry = sum / 10;
    31. sum = sum % 10;
    32. //尾插
    33. ListNode temp = new ListNode(sum);
    34. p.next = temp;
    35. p = temp;
    36. }
    37. return newNode.next;
    38. }
    39. }

    题目 : 

    牛客 BM11 链表相加(二) :

    这个链表加法就和上面这个有点区别 , 但解法都是一样的(压栈法 , 链表法)

    例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

    解析 :

     压栈法

    1. import java.util.*;
    2. /*
    3. * public class ListNode {
    4. * int val;
    5. * ListNode next = null;
    6. * public ListNode(int val) {
    7. * this.val = val;
    8. * }
    9. * }
    10. */
    11. public class Solution {
    12. /**
    13. * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
    14. *
    15. *
    16. * @param head1 ListNode类
    17. * @param head2 ListNode类
    18. * @return ListNode类
    19. */
    20. public ListNode addInList (ListNode head1, ListNode head2) {
    21. // write code here
    22. //压栈
    23. Stack sa = new Stack<>();
    24. Stack sb = new Stack<>();
    25. while(head1 != null){
    26. sa.push(head1.val);
    27. head1 = head1.next;
    28. }
    29. while(head2 != null){
    30. sb.push(head2.val);
    31. head2 = head2.next;
    32. }
    33. //虚拟节点
    34. ListNode newNode = new ListNode(-100);
    35. //进位
    36. int carry = 0;
    37. while(!sa.empty() || !sb.empty() || carry == 1){
    38. int x = sa.empty() ? 0 : sa.pop();
    39. int y = sb.empty() ? 0 : sb.pop();
    40. int sum = x + y + carry;
    41. carry = sum / 10;
    42. sum = sum % 10;
    43. ListNode p = new ListNode(sum);
    44. p.next = newNode.next;
    45. newNode.next = p;
    46. }
    47. return newNode.next;
    48. }
    49. }

    这期就到这里 , 下一关见!

  • 相关阅读:
    阿里云服务器本地地域武汉、福州和南京详细介绍
    双写绕过 [极客大挑战 2019]BabySQL 1
    阿里云轻量应用服务器Ubuntu20.04上手体验与基本配置(图形界面,ssh,代理等)
    云行 | 让数据奔驰在“云”间,天翼云助力贵州筑牢算力底座
    《代码随想录》刷题笔记——哈希表篇【java实现】
    体态识别算法在 Android 端部署实例
    Java面向对象编程(五)
    MySQL-索引优化和查询优化
    java高并发系列-第3天:有关并行的两个重要定律
    tensorflow2.x --------------------DenseNet-----------------------------
  • 原文地址:https://blog.csdn.net/sytdsqzr/article/details/134006443