数据结构 4 之链表和递归


  

1 leetcode第23题

题目描述

删除链表中等于给定值 val 的所有节点。

示例:

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
public class ListNode {

    public int val;
    public ListNode next;

    public ListNode(int x) {
        val = x;
    }
}
class Solution {

    public ListNode removeElements(ListNode head, int val) {

        //判断头节点就是该val值
        while(head != null && head.val == val){
            ListNode delNode = head;
            //头节点后移
            head = head.next;
            delNode.next = null;
        }

        if(head == null)
            return head;

        ListNode prev = head;
        while(prev.next != null){
            if(prev.next.val == val) {
                ListNode delNode = prev.next;
                prev.next = delNode.next;
                delNode.next = null;
                //注意这里prev 不用后移,因为删除之后prev的下一个节点已经删除
            }
            else
                prev = prev.next;
        }

        return head;
    }

    /**
     * 在lettcode中提交代码不用考虑内存回收的问题,代码可以简化
     * @param head
     * @param val
     * @return
     */
    public ListNode removeElements2(ListNode head, int val) {

        //判断头节点就是该val值
        while(head != null && head.val == val){
            head = head.next;
        }

        if(head == null)
            return head;

        ListNode prev = head;
        while(prev.next != null){
            if(prev.next.val == val) {
                prev.next = prev.next.next;
            }
            else
                prev = prev.next;
        }

        return head;
    }
    /*
     * 使用虚拟头节点 简化代码
     */
    public ListNode removeElements3(ListNode head, int val) {

        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;

        ListNode prev = dummyHead;
        while(prev.next != null){
            if(prev.next.val == val)
                prev.next = prev.next.next;
            else
                prev = prev.next;
        }

        return dummyHead.next;
    }
}

2 本地调试

public class ListNode {

    public int val;
    public ListNode next;

    public ListNode(int x) {
        val = x;
    }

    // 链表节点的构造函数
    // 使用arr为参数,创建一个链表,当前的ListNode为链表头结点
    public ListNode(int[] arr){

        if(arr == null || arr.length == 0)
            throw new IllegalArgumentException("arr can not be empty");

        this.val = arr[0];
        ListNode cur = this;
        for(int i = 1 ; i < arr.length ; i ++){
            cur.next = new ListNode(arr[i]);
            cur = cur.next;
        }
    }

    // 以当前节点为头结点的链表信息字符串
    @Override
    public String toString(){

        StringBuilder s = new StringBuilder();
        ListNode cur = this;
        while(cur != null){
            s.append(cur.val + "->");
            cur = cur.next;
        }
        s.append("NULL");
        return s.toString();
    }
}
class Solution {

    public ListNode removeElements(ListNode head, int val) {

        while(head != null && head.val == val){
            ListNode delNode = head;
            head = head.next;
            delNode.next = null;
        }

        if(head == null)
            return head;

        ListNode prev = head;
        while(prev.next != null){
            if(prev.next.val == val) {
                ListNode delNode = prev.next;
                prev.next = delNode.next;
                delNode.next = null;
            }
            else
                prev = prev.next;
        }

        return head;
    }

    public static void main(String[] args) {

        int[] nums = {1, 2, 6, 3, 4, 5, 6};
        ListNode head = new ListNode(nums);
        System.out.println(head);

        ListNode res = (new Solution()).removeElements(head, 6);
        System.out.println(res);
    }
}
1->2->6->3->4->5->6->NULL
1->2->3->4->5->NULL

Process finished with exit code 0
class Solution2 {

    public ListNode removeElements(ListNode head, int val) {

        while(head != null && head.val == val)
            head = head.next;

        if(head == null)
            return head;

        ListNode prev = head;
        while(prev.next != null){
            if(prev.next.val == val)
                prev.next = prev.next.next;
            else
                prev = prev.next;
        }

        return head;
    }

    public static void main(String[] args) {

        int[] nums = {1, 2, 6, 3, 4, 5, 6};
        ListNode head = new ListNode(nums);
        System.out.println(head);

        ListNode res = (new Solution2()).removeElements(head, 6);
        System.out.println(res);
    }
}
1->2->6->3->4->5->6->NULL
1->2->3->4->5->NULL

Process finished with exit code 0
class Solution3 {

    public ListNode removeElements(ListNode head, int val) {

        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;

        ListNode prev = dummyHead;
        while(prev.next != null){
            if(prev.next.val == val)
                prev.next = prev.next.next;
            else
                prev = prev.next;
        }

        return dummyHead.next;
    }

    public static void main(String[] args) {

        int[] nums = {1, 2, 6, 3, 4, 5, 6};
        ListNode head = new ListNode(nums);
        System.out.println(head);

        ListNode res = (new Solution3()).removeElements(head, 6);
        System.out.println(res);
    }

1->2->6->3->4->5->6->NULL
1->2->3->4->5->NULL

Process finished with exit code 0

3 递归基础和递归的宏观语义

1、本质上就是将原来的问题转化为更小的同一问题

在这里插入图片描述

public class Sum {

    public static int sum(int[] arr){
        return sum(arr, 0);
    }

    // 计算arr[l...n)这个区间内所有数字的和
    private static int sum(int[] arr, int l){
        if(l == arr.length)
            return 0;
        return arr[l] + sum(arr, l + 1);
    }

    public static void main(String[] args) {

        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8};
        System.out.println(sum(nums));
    }
}

在这里插入图片描述

4 链表的天然递归结构性质

在这里插入图片描述
用递归解决链表中删除元素的问题
在这里插入图片描述

class Solution3 {

    public ListNode removeElements(ListNode head, int val) {

        if (head == null) {
            return null;
        }
        ListNode res = removeElements(head.next,val);
        //如果当前head的值就是要查找的值,则返回更小的链表
        if(head.val == val) {
            return res;
        } else {
            head.next = res;
            return head;
        }
    }
    //将上一步进行化简
    public ListNode removeElements2(ListNode head, int val) {

        if (head == null) {
            return null;
        }
        head.next = removeElements2(head.next,val);
        return head.val == val ? head.next : head;
    }



    public static void main(String[] args) {

        int[] nums = {1, 2, 6, 3, 4, 5, 6};
        ListNode head = new ListNode(nums);
        System.out.println(head);

        ListNode res = (new Solution3()).removeElements2(head, 6);
        System.out.println(res);
    }
}

5 递归的的微观解读

1、递归函数的调用,本质就是普通函数的调用
2、只不过调用的函数是自己本身

回顾之前的数组求和函数的递归调用

public class Sum {

    public static int sum(int[] arr){
        return sum(arr, 0);
    }

    // 计算arr[l...n)这个区间内所有数字的和
    private static int sum(int[] arr, int l){
        if(l == arr.length)
            return 0;
        int x = sum(arr,l + 1);
        int res = arr[l] + x;
        return res ;
    }
}

在这里插入图片描述
再回顾使用递归方法删除链表中相同元素的问题
在这里插入图片描述
开始进行返回
在这里插入图片描述

总结:
1、递归的调用是有代价的:函数调用 + 系统栈空间

6 递归算法的调试

public class Solution {

    public ListNode removeElements(ListNode head, int val, int depth) {

        String depthString = generateDepthString(depth);

        System.out.print(depthString);
        System.out.println("Call: remove " + val + " in " + head);

        if(head == null){
            System.out.print(depthString);
            System.out.println("Return: " + head);
            return head;
        }

        ListNode res = removeElements(head.next, val, depth + 1);
        System.out.print(depthString);
        System.out.println("After remove " + val + ": " + res);

        ListNode ret;
        if(head.val == val)
            ret = res;
        else{
            head.next = res;
            ret = head;
        }
        System.out.print(depthString);
        System.out.println("Return: " + ret);

        return ret;
    }

    private String generateDepthString(int depth){
        StringBuilder res = new StringBuilder();
        for(int i = 0 ; i < depth ; i ++)
            res.append("--");
        return res.toString();
    }

    public static void main(String[] args) {

        int[] nums = {1, 2, 6, 3, 4, 5, 6};
        ListNode head = new ListNode(nums);
        System.out.println(head);

        ListNode res = (new Solution()).removeElements(head, 6, 0);
        System.out.println(res);
    }

}
1->2->6->3->4->5->6->NULL
Call: remove 6 in 1->2->6->3->4->5->6->NULL
--Call: remove 6 in 2->6->3->4->5->6->NULL
----Call: remove 6 in 6->3->4->5->6->NULL
------Call: remove 6 in 3->4->5->6->NULL
--------Call: remove 6 in 4->5->6->NULL
----------Call: remove 6 in 5->6->NULL
------------Call: remove 6 in 6->NULL
--------------Call: remove 6 in null
--------------Return: null
------------After remove 6: null
------------Return: null
----------After remove 6: null
----------Return: 5->NULL
--------After remove 6: 5->NULL
--------Return: 4->5->NULL
------After remove 6: 4->5->NULL
------Return: 3->4->5->NULL
----After remove 6: 3->4->5->NULL
----Return: 3->4->5->NULL
--After remove 6: 3->4->5->NULL
--Return: 2->3->4->5->NULL
After remove 6: 2->3->4->5->NULL
Return: 1->2->3->4->5->NULL
1->2->3->4->5->NULL

Process finished with exit code 0

7 链表的其他形式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值