自刷代码随想录Day04

lc206:反转链表(简单)
题目描述:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
在这里插入图片描述
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        while (cur.next != null) {
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        cur.next = pre;
        head = cur;
        return head;
    }
}

解题心得:
这是一道简单题,对于该题确实没有什么可说的,但是反转链表的思想是比较常见的,要学会应用于其它地方。
该方法使用的是双指针,首先我们需要定义一个指针cur指向head头指针(我们要习惯不要使用head指针来操作链表),定义一个pre指针为null,这个是比较重要的,尽量在可以的情况下保持头指针的操作和后面指针操作相同。然后就是暂存指针tmp,防止指针丢失的作用。


lc19:删除链表的倒数第 N 个结点(中等)
题目描述:

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode fastIndex = head;
        ListNode slowIndex = head;
        while (n-- > 0 && fastIndex != null) {
            fastIndex = fastIndex.next;
        }
        if (fastIndex == null) {
            if (head.next == null) {
                head = null;
                return head;
            }
            head = head.next;
            return head;
        }
        fastIndex = fastIndex.next;
        while (fastIndex != null) {
            fastIndex = fastIndex.next;
            slowIndex = slowIndex.next;
        }
        slowIndex.next = slowIndex.next.next;
        return head;
    }
}

解题心得:
说实在的,这道题我还是写了蛮久,就是因为每次需要调试特殊情况。即使是现在的代码,感觉也还是很模糊,并没有做到清晰明了。
说说题,首先我们一看是删除倒数第n个节点,可以想象成一个滑动窗口的首尾,那么这就是一个比较明显的快慢指针问题。
我们的想法就是快指针移到最尾巴,慢指针刚好要比快指针慢n+1个位置(之所以是n+1而不是n,是因为我们将慢指针后面的那个空间定义为待删除数据)
那么我们需要来讨论一些特殊情况:
1)题目没有告诉如果失败会怎样,那么我们默认n一个符合要求的,不存在n<0或者大于链表长度的情况。
2)我们要考虑当快指针比慢指针快n-1时,也就是n正好等于链表长度,那么我们要删除的就是head的那个节点,我们在正常删除节点的时候,此时又有个特殊情况,如果这个链表就只有一个head节点,也就是n和链表长度都等于1的情况,我们删除的方法又是和常规操作不一样的。
3)当n小于了链表长度,我们就可以正常遍历进行删除了,这个疑点并不大,只是在两个指针同时移动之前,我们为什么需要先把快指针移动一下?这个也是比较困惑的地方,因为我们快慢指针停止的终点是fastIndex == null,所以导致我们不能在理想状态下停到最尾巴上,所以我们需要将快慢指针的差距再拉开一个节点。(如果我们能够使得fastIndex停在最后一个位置,是不是就可以不用先移动?是的。------ 我们只需要将后面停止条件设置成fastIndex.next != null就行了)

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode cur = head.next;
        head.next = swapPairs(cur.next);
        cur.next = head;
        return cur;
    }
}

该代码参考了别人的代码。
首先这道题可以使用递归我就没想到,这个还是我太菜了。
递归三部曲:
1)找终止条件:本题终止条件很明显,当递归到链表为空或者链表只剩一个元素的时候,没得交换了,自然就终止了。
2)找返回值:返回给上一层递归的值应该是已经交换完成后的子链表。(交换后的自链表头指针)
3)单次的过程:因为递归是重复做一样的事情,所以从宏观上考虑,只用考虑某一步是怎么完成的。我们假设待交换的俩节点分别为head和cur,cur的应该接受上一级返回的子链表(参考第2步)。接收了之后,就相当于是一个含三个节点的链表交换前两个节点,就很简单了,想不明白的画画图就ok。
递归精髓:每一级的操作是一样的

递归方面的推荐看一下这个博客:递归三部曲

递归套路解题:
lc104:二叉树的最大深度

题目描述:

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return Math.max(left, right) + 1;
    }
}

说实话,这道题自己第一遍还是需要看题解,刷leetcode就是这样,需要重复多次才能有收获。
终止条件:root == null, 这里的root是指每个子节点的根节点。
返回值:首先看返回值是否可以和该算法最终返回值一致,若一致则非常容易找到。本题返回值为子树的最大深度。
单次返回过程:就是分别求左子树和右子树的最大深度,然后比较左右子树深度,取大者。

lc110:平衡二叉树

题目描述:

给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
在这里插入图片描述
在这里插入图片描述

class Solution {
    public boolean isBalanced(TreeNode root) {
        int res = isBFS(root);
        if (res == -1) {
            return false;
        }
        return true;
    }

    public int isBFS (TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = isBFS(root.left);
        int right = isBFS(root.right);
        if (Math.abs(left - right) <= 1 && left != -1 && right != -1) {
            return Math.max(left, right) + 1;
        }
        return -1;
    }
}

本题AC受到上一题影响颇深,主要纠结的点是返回值为什么?该题解需要的返回值为Boolean类型,但是我们感觉我们的递归类型不能以Boolean来作为返回值,不然上层递归无法拿到下层递归返回的结果,无法判断上层是否为平衡二叉树。
由此想到了标记法,就比如我们返回的是平衡二叉树的最大深度,但如果该子树不是平衡二叉树,我们就做上标记,返回一个特殊的int类型的结果给上层(比如-1),上层判断如果下层返回-1,则直接返回给自己的上层-1,如不是,则正常就行判断自己是不是平衡二叉树,以此类推。


lc24:两两交换链表中的节点(中等)
题目描述:

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
在这里插入图片描述

面试题 02.07. 链表相交(简单)
题目描述:

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = LenA_B(headA);
        int lenB = LenA_B(headB);
        ListNode curA = headA;
        ListNode curB = headB;
        while (lenA > lenB) {
            curA = curA.next;
            lenA--;
        }
        while (lenA < lenB) {
            curB = curB.next;
            lenB--; 
        }
        while (curA != null) {
            if (curA == curB) {
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }

    public int LenA_B (ListNode head) {
        ListNode cur = head;
        int len = 0;
        while (cur != null) {
            len ++;
            cur = cur.next;
        }
        return len;
    }
}

解题心得:
总的来说这道题还是比较简单的,我们在需要链表长度时是可以遍历链表来求其长度的。
要求出两个链表相交的开始,我们知道相交之后的所有部分,他们的节点时相同的,就意味着我们需要尾对齐,更长的链表,链表前的部分肯定是不符合要求的,算了这个还是直接上图比较清晰。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值