算法学习1

目录

学习目标:

学习内容:

学习时间:

学习产出:

描述

知识点学习

   栈的基本方法

双链表的基本操作

创建一个新的节点:

题解

1,使用栈解决

2,双链表求解

3,递归解决


学习目标:

链表


学习内容:

反转链表


 

学习时间:

每天

 


学习产出:

描述

给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

数据范围: 0≤n≤10000\leq n\leq10000≤n≤1000

要求:空间复杂度 O(1)O(1)O(1) ,时间复杂度 O(n)O(n)O(n) 。

如当输入链表{1,2,3}时,

经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。

知识点学习

   栈的基本方法

  1. public stack();创建栈
  2.  public E push(); 入栈
  3.  public E pop(); 出栈(删除栈顶元素)
  4.  public E peek()查看栈顶元素(不删除)
  5.  public boolean empty(); 判断栈是否为空

双链表的基本操作

创建一个新的节点

ListNode list=new ListNode(0) 初始化一个节点值为0的空节点,最常用最正规写法

插入

将链表的该结点指向的节点放到待插入的节点的后面,然后让该结点指向待插入节点即可。

 删除

让所需要删除的节点等于它下一个节点。

题解

1,使用栈解决

链表的反转是老生常谈的一个问题了,同时也是面试中常考的一道题。最简单的一种方式就是使用栈,因为栈是先进后出的。实现原理就是把链表节点一个个入栈,当全部入栈完之后再一个个出栈,出栈的时候在把出栈的结点串成一个新的链表。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

import java.util.Stack;

public class Solution {

public ListNode ReverseList(ListNode head) {

    Stack<ListNode> stack= new Stack<>();

    //把链表节点全部摘掉放到栈中

    while (head != null) {

        stack.push(head);

        head = head.next;

    }

    if (stack.isEmpty())

        return null;

    ListNode node = stack.pop();

    ListNode dummy = node;

    //栈中的结点全部出栈,然后重新连成一个新的链表

    while (!stack.isEmpty()) {

        ListNode tempNode = stack.pop();

        node.next = tempNode;

        node = node.next;

    }

    //最后一个结点就是反转前的头结点,一定要让他的next

    //等于空,否则会构成环

    node.next = null;

    return dummy;

}

}

2,双链表求解

双链表求解是把原链表的结点一个个摘掉,每次摘掉的链表都让他成为新的链表的头结点,然后更新新链表。他每次访问的原链表节点都会成为新链表的头结点,最后再来看下代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public ListNode ReverseList(ListNode head) {

    //新链表

    ListNode newHead = null;

    while (head != null) {

        //先保存访问的节点的下一个节点,保存起来留着下一步访问的

        ListNode temp = head.next;

        //每次访问的原链表节点都会成为新链表的头结点,

        //其实就是把新链表挂到访问的原链表节点的后面就行了

        head.next = newHead;

        //更新新链表

        newHead = head;

        //重新赋值,继续访问

        head = temp;

    }

    //返回新链表

    return newHead;

}

3,递归解决

我们再来回顾一下递归的模板,终止条件,递归调用,逻辑处理。

1

2

3

4

5

6

7

8

9

10

11

public ListNode reverseList(参数0) {

    if (终止条件)

        return;

    逻辑处理(可能有,也可能没有,具体问题具体分析)

    //递归调用

    ListNode reverse = reverseList(参数1);

    逻辑处理(可能有,也可能没有,具体问题具体分析)

}

终止条件就是链表为空,或者是链表没有尾结点的时候,直接返回

1

2

if (head == null || head.next == null)

    return head;

递归调用是要从当前节点的下一个结点开始递归。逻辑处理这块是要把当前节点挂到递归之后的链表的末尾,看下代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public ListNode ReverseList(ListNode head) {

    //终止条件

    if (head == null || head.next == null)

        return head;

    //保存当前节点的下一个结点

    ListNode next = head.next;

    //从当前节点的下一个结点开始递归调用

    ListNode reverse = ReverseList(next);

    //reverse是反转之后的链表,因为函数reverseList

    // 表示的是对链表的反转,所以反转完之后next肯定

    // 是链表reverse的尾结点,然后我们再把当前节点

    //head挂到next节点的后面就完成了链表的反转。

    next.next = head;

    //这里head相当于变成了尾结点,尾结点都是为空的,否则会构成环

    head.next = null;

    return reverse;

}

因为递归调用之后head.next节点就会成为reverse节点的尾结点,我们可以直接让head.next.next = head;,这样代码会更简洁一些,看下代码

1

2

3

4

5

6

7

8

public ListNode ReverseList(ListNode head) {

    if (head == null || head.next == null)

        return head;

    ListNode reverse = ReverseList(head.next);

    head.next.next = head;

    head.next = null;

    return reverse;

}

这种递归往下传递的时候基本上没有逻辑处理,当往回反弹的时候才开始处理,也就是从链表的尾端往前开始处理的。我们还可以再来改一下,在链表递归的时候从前往后处理,处理完之后直接返回递归的结果,这就是所谓的尾递归,这种运行效率要比上一种好很多

1

2

3

4

5

6

7

8

9

10

11

public ListNode ReverseList(ListNode head) {

    return reverseListInt(head, null);

}

private ListNode reverseListInt(ListNode head, ListNode newHead) {

    if (head == null)

        return newHead;

    ListNode next = head.next;

    head.next = newHead;

    return reverseListInt(next, head);

}

尾递归虽然也会不停的压栈,但由于最后返回的是递归函数的值,所以在返回的时候都会一次性出栈,不会一个个出栈这么慢。但如果我们再来改一下,像下面代码这样又会一个个出栈了

1

2

3

4

5

6

7

8

9

10

11

12

public ListNode ReverseList(ListNode head) {

    return reverseListInt(head, null);

}

private ListNode reverseListInt(ListNode head, ListNode newHead) {

    if (head == null)

        return newHead;

    ListNode next = head.next;

    head.next = newHead;

    ListNode node = reverseListInt(next, head);

    return node;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值